Troubleshooting agents
Find your error message below, then apply the fix. The headings use the real error strings, so searching this page for what you saw will land you on the right one.
Every API error arrives in the same JSON wrapper: {"error": "<message>", "request_id": "<id>"}. The request_id identifies your one request in the platform's records, so include it when you contact support.
Deploying
"this project cannot deploy yet" — no Crusoe Cloud credential
Full message (409 on deploy):
this project cannot deploy yet: its container images are built into your own Crusoe Cloud container registry, and no Crusoe Cloud credential is mapped to this project. A project admin sets one with PUT /v1/projects/{id}/crusoe-cloud {"access_key_id":"...","secret_key":"..."} (in the console: Project Settings), then deploy again. The repository itself is created for you on the first deploy - there is nothing to pre-create. Nothing was built and your stored source was not touched.
Cause: your project has no Crusoe Cloud connection. Everything the platform builds for you is stored in a repository in your own Crusoe Cloud Registry — your account, your quota, your bill — so there is nowhere to put the image until a credential is saved. The refusal arrives at submit, before any build runs, which is why it is a clean 409 rather than a failure buried in build output.
Fix: a project admin connects the project once. In the console the page is Project Settings; from the CLI:
printf %s "$CRUSOE_SECRET_KEY" | platformctl crusoe-cloud connect --access-key-id 'CRUSOEEXAMPLEKEYID'
Then deploy again. The step, with all three interfaces, is connect your Crusoe Cloud account; the full reference is Crusoe Cloud integration.
Nothing was consumed by the refused attempt: no image was built, and an agent that was already deployed keeps running on the version it has. A project that was already connected never sees this.
Two neighbours worth telling apart:
409—this deploy could not be attached to a project, and images are built into the project's own Crusoe Cloud container registry - so there is no registry to push to. ...means the request resolved to no project at all, so there was no credential to look up. Sign in with a credential that belongs to a project, or name it with?project=<slug>.400—the stored Crusoe Cloud credential is not usableand409—the stored Crusoe Cloud mapping credential is invalid or unparseable; re-map the project ...both mean a credential is stored but cannot be used. Save the connection again with a valid key.503—the project secret store is not configured, so this project's Crusoe Cloud credential cannot be read. This is a platform configuration problem, not yours.is not about your project at all. Retry, and ask your administrator if it persists.
"this project is at its service limit"
Full message (409 on deploy):
this project is at its service limit (10 / 10): deploying needs at least one more service and cannot proceed. Delete an agent or function, or ask an admin to raise the project's service quota, then deploy.
Cause: every agent and function counts against the project's service quota, and the project is full.
Fix: exactly what the message says — platformctl delete <agent> something you no longer need, or ask a project admin to raise the quota (see quotas and audit), then deploy again.
There is a related version of this that appears when the quota fills up during a deploy. The agent sticks at deploying, and its message field reads This project is at its service limit (10 / 10), so the new revision cannot get a network route yet - .... Same cause, same fix. The deploy finishes on its own once there is room.
"missing or invalid 'name' (must be a lowercase DNS label)"
Cause: agent names must match ^[a-z]([a-z0-9-]{0,61}[a-z0-9])?$. In words: lowercase letters, digits, and hyphens, starting with a letter, at most 63 characters. So MyAgent, my_agent, and my agent are all invalid. On routes that take the name in the URL, the same rule produces 400 invalid agent name (must be a lowercase DNS label).
Fix: rename to something like my-agent. Names are immutable after deploy — pick one you can live with.
"a build is already in progress for agent"
Full message: 409 a build is already in progress for agent research-buddy.
Cause: two deploys of the same agent raced; only one build may run at a time.
Fix: wait for the in-flight build to finish (platformctl status <agent>), then redeploy. If a build crashed and left a stale claim, it becomes reclaimable after 30 minutes — retry then.
State is failed after a deploy
Cause: the build itself failed — usually a bad requirements.txt pin or a broken Dockerfile step.
Fix: read the build output. There is no separate build-log endpoint; the tail of the build output (up to 4,000 characters) lands in the agent's message field:
platformctl status my-agent
Look near the end of that output for the failing pip install or compile error.
One note for LangGraph and CrewAI agents. If a version you pinned in requirements.txt conflicts with one the base image already has, the build fails right here. That is deliberate: a clear build error beats an instance that crashes on import in production.
"the image built, but pushing it to ... was refused"
Cause: your code compiled and the image was produced; the refusal came from your own Crusoe Cloud Registry at the last step. The message names the registry host and then the reason:
| Reason it gives | What to do |
|---|---|
the registry credential was rejected. ... | The credential the platform mints from your stored Crusoe Cloud key was refused. Save the connection again with a valid key — platformctl crusoe-cloud connect — and deploy again. This is also what a rotated or revoked key looks like. |
the registry denied the push. ... | The key is valid but not allowed to write to your container registry. Check its permissions in Crusoe Cloud, then deploy again. |
the registry is out of space. ... | Your registry is full. Retention there is yours to set: delete images you no longer need, or raise the quota, then deploy again. Nobody else's images are in it. |
This is deliberately worded to say the push failed rather than the build, because the same words appearing anywhere else in a build log usually mean a private base image in your FROM line — which is genuinely yours to fix in the Dockerfile.
"could not import root_agent from /app/agent/agent.py"
Full message (in the agent's message field, after the instance fails to start over and over):
could not import `root_agent` from /app/agent/agent.py - the agent image must define a module-level `root_agent` in agent.py
Cause: the build succeeded, but your code doesn't meet the framework's entry-point contract, so the harness can't load it.
Fix: export the required module-level symbol for your framework:
| Framework | File | Must export |
|---|---|---|
| ADK | agent.py | root_agent |
| LangGraph | graph.py | graph (a compiled StateGraph) |
| CrewAI | crew.py | crew (a crewai.Crew or a zero-argument factory) |
See ADK, LangGraph, and CrewAI.
"'runtime' only applies to framework=function"
Cause: you sent a runtime form field (e.g. nodejs) while deploying an agent. Agents are Python; only functions choose a runtime.
Fix: drop the runtime field, or deploy a function if that's what you meant.
"no source is stored for this agent - deploy it once from the CLI or upload files first"
Cause: you called POST /v1/agents/{name}/redeploy (or the console editor's deploy button), but the platform has no stored source for this agent — source storage is best-effort.
Fix: deploy once with platformctl deploy <dir> (which stores the source), or create files via the files API, then redeploy.
Ownership and visibility (the 404 rule)
"unknown agent" — but you're sure it exists
Full message: 404 unknown agent: research-buddy.
Cause: on this platform, "doesn't exist" and "exists but isn't yours" are deliberately the same 404. The API never confirms that a resource you cannot access is there at all. So if someone else owns an agent with that name, you get this same 404 — including when you try to deploy over it.
Fix: check you're signed in as the right user (platformctl whoami) and pointed at the right project (--project or platformctl config set-project). If a teammate owns the agent, ask them or a project admin.
"this agent has no recorded owner, so only a project admin can manage it"
Full message (403): this agent has no recorded owner, so only a project admin can manage it (a project admin can adopt it by redeploying it). The deploy-time variant: an agent named research-buddy already exists and has no recorded owner, so only a project admin can redeploy it.
Cause: the agent was deployed without a user identity attached to the request, so there is no owner to match you against.
Fix: have a project admin redeploy it — that adopts it and records an owner.
"the agent name ... exists in more than one project"
Full message (409): the agent name research-buddy exists in more than one project; add ?project=<slug> to say which one, or sign in so it resolves within your project.
Cause: agents are addressed by name, and two projects you can see both have one with this name.
Fix: add ?project=<slug> to the request (or --project on the CLI), or sign in so resolution happens inside your own project.
Invoking
"message is required"
Cause: the invoke body was missing a message, or it was blank.
Fix: send {"message": "..."}. See invoke for the full shape.
"session_id chosen by an unauthenticated caller must be at least 24 characters"
Full message (400):
session_id chosen by an unauthenticated caller must be at least 24 characters of unguessable randomness (or omit it and the platform will generate one). A short, guessable id would let anyone else read this conversation.
Cause: you invoked anonymously with a short, guessable session_id like s1. Anyone who guessed it could continue — and read — your conversation.
Fix: omit session_id and save the one the platform returns, or generate 24+ random characters, or authenticate.
"memorize requires authentication"
Full message (401): memorize requires authentication: it writes durable memory that later callers read back. Invoke without 'memorize', then call POST /v1/agents/{name}/sessions/{id}/memorize with a session token.
Cause: memorize writes to the shared memory bank, and every future caller of this agent reads from it. Writing therefore always requires a signed-in caller, even though invoking does not.
Fix: platformctl login, then use platformctl memorize <agent> --session <id> or send a bearer token.
The agent answers, but turn 2 forgot turn 1
Cause: the session_id changed between calls, or you supplied two different user_id values yourself.
Fix: reuse the same session_id on every turn (--session on the CLI). If you set user_id manually, keep it constant too — or omit it and the platform derives a stable one. See sessions.
First invoke after idle is slow, or times out
Cause: a cold start. Idle agents scale to zero, so the first request has to start a fresh instance, boot the harness, and import your code. All of that happens inside the invoke timeout, which is 60 seconds by default. Heavy imports can push the first call past that line. The retry then reaches an instance that is already running and succeeds.
Fix: retry once — a running instance answers fast. To remove cold starts on an agent where speed matters, set min_scale: 1 in its compute config, which keeps one instance always on. That is the Configure modal in the console, or PATCH /v1/agents/{name}/config. See traffic and revisions.
The agent replies with model authentication errors
Cause: no model credential is in force — the platform default is missing and the agent has no MODEL_API_KEY secret of its own.
Fix: check first, without exposing anything. The agent's own URL serves GET /debug/config with no credential required, and it reports model_key_present: true/false alongside the resolved model. If that reads false, set a key with platformctl secrets set <agent> MODEL_API_KEY=sk-.... See secrets and env.
"this is a management endpoint and requires authentication"
Full message (401), trimmed to the part that applies to you:
this is a management endpoint and requires authentication. Sign in (POST /v1/auth/login) and send 'Authorization: Bearer <token>'
Cause: deploy, logs, secrets, files, revisions, and session browsing all require a credential. Only invoke is open by default.
Fix: run platformctl login, or send the header Authorization: Bearer $CAI_TOKEN. For a script with no human at the keyboard, use a service-account API key instead — see service accounts and API keys.
Tools and MCP servers
"ERROR: SecretError: crusoe.secret is not configured" — or a KeyError — from a tool
Cause: the tool is sandboxed. A sandboxed tool call runs in a single-use container started from your agent's image with the environment stripped to PYTHONUNBUFFERED and PORT, and with egress that excludes every private range — the platform's own internal addresses included. So os.environ[...] raises KeyError, crusoe.secret() fails closed because the three variables it needs (CAI_API_URL, CAI_PROJECT_ID, CAI_PROJECT_KEY) are not there, and an internal platform address times out.
How it reaches you: never as an HTTP error. The tool result is handed to the model as ordinary text, and the model answers around it — so the invoke succeeds and the answer is merely wrong. The tell is a result beginning ERROR::
- In a streaming invoke, the
tool_resultline:{"type":"tool_result","name":"...","result":"ERROR: ..."} - In a session transcript, the
function_responsepart for that call
A failure at import names the module rather than the variable — ERROR: could not import agent: ... KeyError: 'CACHE_HOST' — because the sandbox re-imports your module before it looks up the function.
Fix: move the tool to an MCP server, which is given the credential and the network. If you fully trust the tool code, platformctl secrets set my-agent TOOL_SANDBOX=false runs it in the agent process instead — as a per-agent secret, because PATCH /v1/agents/{name}/env refuses that name with a 400. The rule for deciding: tools.
My agent has no MCP tools
Cause: MCP_SERVERS is captured into the agent's revision at deploy, from the MCP servers in the project that were ready at that moment. A server created — or first reaching ready — after the agent was deployed never reaches it. The agent starts cleanly, logs nothing unusual, and answers from the model alone.
Fix: wait for the server, then redeploy the agent:
platformctl mcp get doc-search-mcp # wait until state is ready
platformctl deploy ./my-agent --name my-agent
There is no way to read MCP_SERVERS back and check: GET /v1/agents/{name}/env returns only the variables you set yourself, and /debug/config carries AGENT_NAME, CHAT_MODEL and EMBED_MODEL and nothing else. Verify by invoking the agent and looking for the server's tools in tool_calls. Do not use platformctl logs my-agent --history | grep "tool sandbox" for this one — that startup line reports the tools you wrote, so an agent whose only tools come from MCP servers reports nothing to isolate whether or not a server is attached.
A named server that is genuinely missing fails loudly instead, which is the point of naming it:
MCP server(s) not attached to this project: doc-serch-mcp. Attached: weather-tools
That is crusoe_core.UnknownMCPServer from mcp_toolsets(names=...) / mcp_tools(names=...), and it means the name is spelled wrong or that server is not ready. See connect agents and clients.
Sessions, memory, and logs
"session browsing is not configured"
Full message (503): session browsing is not configured: the control plane has no CAI_INTERNAL_TOKEN, so it cannot authenticate to the agent's read surface.
Cause: the control plane requires an internal credential (CAI_INTERNAL_TOKEN) to read transcripts from agents. This is a platform configuration requirement.
Fix: ask your administrator to configure CAI_INTERNAL_TOKEN on the platform.
"the user_id query parameter is required"
Cause: GET /v1/agents/{name}/sessions lists sessions per user; it needs ?user_id=.
Fix: list users first (GET /v1/agents/{name}/users), then pass one id. See sessions.
"agent ... has no running instances: it is scaled to zero"
Full message (200, not an error):
agent research-buddy has no running instances: it is scaled to zero, which is normal for an idle serverless agent - it cold-starts on the next invoke. For logs from earlier runs, use GET /v1/agents/research-buddy/logs/history.
Cause: the agent is idle. Live logs need a running instance.
Fix: nothing is wrong. Use platformctl logs <agent> --history for earlier runs — history survives scale-to-zero and is retained 14 days by default. See logs.
"--follow and --history are mutually exclusive"
Full message: --follow and --history are mutually exclusive: --history reads persisted logs, --follow tails a running instance.
Fix: pick one: -f to tail the running instance, --history for persisted lines.
Traffic and revisions
"traffic is required - send the complete split"
Full message (400): traffic is required - send the complete split, e.g. [{"revision_name":"research-buddy-00002","percent":100}].
Cause: set-traffic replaces the entire routing table; an empty or partial body is ambiguous.
Fix: send every revision that should serve, with percentages summing to 100. See traffic and revisions.
"revision ... does not exist for this agent"
Cause: a typo in revision_name, or the revision belongs to a different agent.
Fix: list valid names with GET /v1/agents/{name}/revisions and copy one exactly (e.g. research-buddy-00002).
Still stuck?
- Quote the
request_id. Every error carries one in its envelope; it identifies your exact request in the platform's records. - Known issues — documented edge cases and operational notes.
- Troubleshooting (all services) — errors that are not specific to this service.
- Get help — who to report it to, and what to include.