{"record":{"id":"866626aabe88a662","repo":"Hmbown/CodeWhale","slug":"spawn-image-missing","errorCode":"spawn_image_missing","errorMessage":"docker image \"${image}\" is not present locally","messagePattern":"docker image \"(.+?)\" is not present locally","errorType":"error_code","errorClass":"SpawnError","httpStatus":null,"severity":"error","filePath":"crates/tui/plugins/computer-use/src/spawn.mjs","lineNumber":62,"sourceCode":"  if (r.code !== 0) throw new SpawnError(\"spawn_failed\", `docker ${args[0]} failed: ${trim(r.stderr || r.stdout)}`, r);\n  return r;\n}\n\nexport async function dockerAvailable(command = docker) {\n  const r = await command([\"info\", \"--format\", \"{{.OSType}}\"], { timeoutMs: 10_000 });\n  return r.code === 0 && !r.timedOut && !r.aborted && r.stdout.trim() === \"linux\";\n}\n\n/**\n * The image must exist locally. The plugin's own image is built from\n * docker/Dockerfile on first use; any other image name is the caller's\n * responsibility — we never guess a build context for it.\n */\nasync function ensureImage(image) {\n  const inspect = await docker([\"image\", \"inspect\", image], { timeoutMs: 15_000 });\n  if (inspect.code === 0) return { built: false };\n  if (image !== DEFAULT_IMAGE) {\n    throw new SpawnError(\"spawn_image_missing\", `docker image \"${image}\" is not present locally`);\n  }\n  const r = await docker([\"build\", \"-t\", image, \"-f\", path.join(PLUGIN_ROOT, \"docker\", \"Dockerfile\"), PLUGIN_ROOT], { timeoutMs: 15 * 60_000 });\n  if (r.aborted) throw Object.assign(new ExecError(\"computer request cancelled\", r), { code: \"cancelled\" });\n  if (r.code !== 0) throw new SpawnError(\"spawn_failed\", `docker build ${image} failed: ${trim(r.stderr || r.stdout, 800)}`, r);\n  return { built: true };\n}\n\n/**\n * Start a disposable desktop container and verify the agent answers inside\n * its session. On any failure the container is removed — spawn is\n * transactional: either a live computer comes back or nothing was left.\n */\nexport async function spawnDockerComputer({ id, image = DEFAULT_IMAGE } = {}) {\n  if (!await dockerAvailable()) {\n    throw new SpawnError(\"docker_unavailable\", \"A Linux Docker engine is required — start Docker Desktop in Linux-container mode (or Colima) and spawn again\");\n  }\n  const { built } = await ensureImage(image);\n  const container = `cu-spawn-${id}-${crypto.randomBytes(3).toString(\"hex\")}`;","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/plugins/computer-use/src/spawn.mjs#L44-L80","documentation":"Thrown by ensureImage() when a custom image (anything other than the plugin's DEFAULT_IMAGE) is requested but `docker image inspect` shows it is not present locally. The plugin deliberately never builds or pulls user-supplied images — the caller must provide them locally first.","triggerScenarios":"Calling spawnDockerComputer({ image: \"my-desktop:v2\" }) where the image has never been built or pulled on this machine, so `docker image inspect my-desktop:v2` exits non-zero and image !== DEFAULT_IMAGE.","commonSituations":"Fresh machine or CI runner without the prebuilt image, image tag renamed upstream, prune/cleanup jobs removed the image, or a typo in the image reference.","solutions":["Build or pull the image first: `docker pull <image>` or `docker build -t <image> .`.","Verify the exact reference exists: `docker image ls | grep <image>` (tags must match exactly, including :latest).","If you don't need a custom image, omit the `image` option so the plugin's default image is auto-built.","In CI, add a step that pulls/prepares the image before spawning the computer."],"exampleFix":"// before\nawait spawnDockerComputer({ image: \"team/desktop:v9\" }); // never pulled\n// after\nawait dockerOk([\"pull\", \"team/desktop:v9\"]);\nawait spawnDockerComputer({ image: \"team/desktop:v9\" });","handlingStrategy":"validation","validationCode":"import { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nconst pexec = promisify(execFile);\nasync function imageExists(image) {\n  try { await pexec(\"docker\", [\"image\", \"inspect\", image]); return true; }\n  catch { return false; }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await spawnDockerComputer({ image: custom });\n} catch (e) {\n  if (e?.code === \"spawn_image_missing\") {\n    // fall back to the default image or pull the custom one, then retry\n  }\n}","preventionTips":["Pull or build every custom image before spawnDockerComputer.","Prefer omitting `image` so the plugin's default image is auto-built.","Watch for CI image prunes that remove prebuilt images between runs.","Copy image references exactly, including the tag."],"tags":["docker","image","missing-resource"],"backgroundTag":"resource-not-found","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}