Search Docs
Loading...
Skip to content

Troubleshooting

Find the symptom you see when you start, run, or roll out CoDesign, and the change that fixes it. Some problems stop with an error; others fail silently: the run finishes, but the design is poor.

Calls that fail for a reason the model cannot fix reject with an error whose kind names the cause; isCoDesignError(err) checks for one, and the error reference lists every kind. Terms such as executor and agent runner are in Terminology.

Container Does Not Start#

The executor checks its setup at start and exits when something is wrong. A container that exits at once, or a /health call that gets no answer, has the reason in its log. In the quickstarts, the container is named codesign-executor:

Terminal window
docker logs codesign-executor

A healthy container answers curl http://localhost:8080/health with status 200 and "accepting": true. On Kubernetes, kubectl logs <pod> shows the same log, and kubectl describe pod <pod> shows what Kubernetes itself refused, such as OOMKilled for a container over its memory limit.

The common causes:

  • IMGLY_CESDK_LICENSE is missing or is not a key. Set it to your CoDesign license key, the short string itself. Contact sales to get a CoDesign license key. A CE.SDK license file or a grant (the short-lived license IMG.LY issues for one engine) is refused with the billed executor needs a CoDesign license key, not a license file or grant.
  • The key cannot be activated. At start, the executor activates the key at api.img.ly and exits when that fails. The log says how: could not reach the license server https://api.img.ly/activate: … (a network rule blocks api.img.ly, or an outbound proxy is set without NODE_USE_ENV_PROXY=1 in the container’s environment), the license server answered <status>: …, or the license is <status> (the key is not valid).
  • EXECUTOR_TOKEN is missing. Set it to a secret you make yourself, such as openssl rand -hex 32.

The image also refuses to start as root, with a debugger, under an init program, or with a setting it does not take; the log names which. For the flags and settings to run it with, see Run the Image Hardened.

401 From the Executor#

The executor answers 401 with missing or wrong executor token when the agent runner sends a different bearer token from the one the container was started with. The call rejects with the error kind executor_unauthorized. Pass the container’s EXECUTOR_TOKEN as token to remoteExecutors. In the quickstarts, both read it from the kit’s .env: after changing it, run npm run executor:stop and npm run executor so the container gets the new value, then npm start; the run then gets past its first tool call. GET /health needs no token, so a working /health does not prove the token matches.

Runner and Executor on Different Versions#

The call rejects with the error kind executor_version, and the executor answers HTTP 409. Its message names both sides’ protocol (the version of the messages they exchange) and your runner’s SDK_VERSION. Run imgly/codesign-executor tagged with the exact SDK version your runner installed (npm ls @imgly/codesign-sdk shows it). Two SDK builds on the same protocol are not refused, so pin both ( Versions and Upgrades).

The Session Ends With executor_changed#

The call rejects with executor_changed to your code, not to the model: the conversation’s executor was lost, and the one acquire answered next runs another CE.SDK version, can do other things, or registers other asset sources. Call again, which opens the design on the new executor. You see it during a rollout with old and new executors in one pool; replace the old containers after a deploy ( A New Container for Each Conversation).

A Call Fails With executor_unreachable or executor_capacity#

  • executor_unreachable: acquire answered undefined, or the executor gave no answer (or a proxy in front of it answered 502 or 504). Run more executors, or retry the turn later. On your own machine, the container may still be starting, or restarting after the previous run: once it is up, curl http://localhost:8080/health answers, and docker logs codesign-executor says why it is not.
  • executor_capacity: a design opened while its executor was exiting, and the executor was still exiting after 60 seconds. Retry; acquire then answers a new executor for the conversation ( Find a Conversation’s Executor).

A call that ran past 5 minutes, usually model code in an endless loop, is not one of these. The model reads an error and can try again, and only your own create(), load(), edit(), or export() calls reject, with executor_failed. The executor then exits, and the next call loads the design on a new executor.

402 From the Gateway#

IMG.LY’s AI gateway answers 402 insufficient_credits when the IMG.LY account behind the key is out of credits. Top up the account, then run again.

How the run reports it depends on the agent framework:

  • Vercel AI SDK: generateText throws with the gateway’s error.
  • pi: the run ends without throwing, and the error is in the last message (stopReason: 'error'). Check it before you export, or you export a design the model never finished.
  • Image generation: the tool call rejects with the error kind generation_refused and a message for the person. Show it, or offer a top-up. Retrying does not help until the account has credits.

Exports Are Refused#

An export that the executor does not charge fails with the error kind export_refused. Its message says why, in words you can show the person:

  • The account has no credits left.
  • The license key does not include CoDesign. A plain CE.SDK key starts the engine, but every export is refused. Contact sales to get a CoDesign license key.
  • The export is over a limit: more than 16,000 px on its longer side, 500 pages, or 150 MB.
  • The format is video or audio, which the executor does not export.
  • Metering (IMG.LY’s billing service) answered 429 without Retry-After: “This account has reached its export limit for now.” A limit such as exports per user per day refuses this way.
  • “This export carries no render id; update the SDK.”: the export request came from a runner whose SDK does not send a render id, the id that makes a retried export charge once. Update the runner’s SDK.
  • “The billing route https://api.img.ly/exports/claim could not be reached, so this export was not delivered.”: the container has not reached Metering once since it started. Allow api.img.ly in its egress (outbound network access).

Retrying unchanged does not help, except for the export limit, which lifts with time. Fix the cause first: top up the account, use a CoDesign key, export smaller or in another format, update the SDK, or open the egress. For what the image charges and when it refuses an export, see Billing.

Another Conversation Is Refused#

An executor serves only the first conversation that opens a design on it. A call for any other conversation fails with the error kind executor_bound. Your acquire handed out an executor that another conversation already used. Give each new conversation an unused executor, and the same one while the conversation lasts. The image remembers which conversation it serves in a file on a mounted volume, so a container restarted with that volume stays bound. The quickstarts keep it in memory instead: about 30 seconds after a run releases its design, the container exits and comes back unbound. If you change the conversation between runs, wait for that restart before the next run.

The Model Designs Without Seeing Its Work#

Edits and previews answer with renders, and the model needs to see them as images. When it gets none, nothing fails: the model works blind and cannot fix what it cannot see. Check these:

  • Every part of a tool result reaches the model, images included. With the Vercel AI SDK, toModelOutput hands the renders over as files. Without it, the model reads each render as a long text string.
  • The images sit where your provider takes them. A Chat Completions API, IMG.LY’s gateway included, takes no images inside a tool result. With the Vercel AI SDK, move them into a user message after the result in prepareStep, as imagesAfterToolResults does in the Vercel AI SDK quickstart. pi, the agent library from the pi quickstart, moves them itself when the model entry lists input: ['text', 'image'].
  • The model accepts images. Pick a model that reads images.

The Model Ignores the Design Rules#

End your system prompt with codesign.instructions. They tell the model to read the handbook, IMG.LY’s design rules that the SDK serves to the model, before its first edit, to look at the design after every change, and to judge it before it says it is done. Left out, nothing fails: the model may skip the handbook and finish a design it never checked. With pi, pass no convertToLlm filter that drops system messages: pi sends your system prompt and the tool list together in one system message, so a filter that drops it removes both.

The Run Stops Early#

A run can end before the model is done:

  • A step limit. By default, the Vercel AI SDK ends a run after the first tool call. stopWhen: isStepCount(60) lets the model take up to 60 steps. A run that reaches the limit ends with the design half done.
  • The model’s output limit. A reply cut off at the model’s output limit ends the loop with its tool calls not run, and looks like a finished run. With the Vercel AI SDK, treat any finishReason but 'stop' as a failed run.
  • An error. The gateway or the executor refused a call; see the sections above.

The quickstart scripts export only when the run ended normally, so a run that stops early exports nothing and costs no export. With a designs store, every edit that succeeded is already saved in your storage, so you can continue the design in a new run ( Connect Your Storage).

Next Steps#