Browse the docs

Common quirks and troubleshooting

Skill patterns to catch before you generate, and the errors a self-hosted skill agent most often hits.

Before you startA generated agent, or a skill you are about to convert.View as Markdown

Check the skill before you convert it

Symptom in the skillWhat to do
Scripts hardcode /sessions/<session-id>/... pathsCreate the exact path in the Dockerfile and flag the brittleness. One mkdir usually covers every script.
SKILL.md names a CLI tool, or scripts call subprocess, os.system, or os.popenInstall the binary in the Dockerfile, at the exact path the skill looks for it.
A bootstrap or auth flow references tokens.json or ~/.config/<name>/Do not bake credentials or wire OAuth into the agent. Do the first OAuth login on a laptop with the same skill in Claude Code, upload the tokens to a file share, mount it, and point the skill's env var at the mount.
Imports such as feedparser, youtube-transcript-api, arxiv, or prawAdd them to the dependencies and confirm the container's egress can reach the public internet. Check the skill tolerates one source failing.
Multi-MB outputsFile share for files under 100 MB; blob storage (blobfuse or an upload sidecar) for larger or many files. Note size estimates in the README.
The skill calls other skillsBake every skill it needs into /app/.claude/skills/, say so in the prompt, and use the multi-purpose pattern.
The skill keeps state (state.json, history.db)Mount a file share on the state directory. Per-conversation state needs a context id from the caller; treat that as out of scope for a first version.
The skill needs a newer PythonThe image uses python:3.12-slim. Bump it if needed; never go below 3.10, which the SDK requires.
Scripts call input() or getpass(), or open an editorNot viable unattended. Refactor the skill to take everything through arguments or env first.
The skill imports a package that is not on PyPIStop. That is a blocker.

Errors and what they mean

You seeCause and fix
/health returns not_configuredRead the missing-vars list in the response body's detail.
AMC registration says Unreachable but the container is running/health returned 503 because the health probe is not ready, or the URL redirects. See Deploy and register in AMC.
The agent runs but never invokes the skillCheck /app/.claude/skills/<skill-name>/SKILL.md exists in the container, SKILL_NAME matches the frontmatter name:, allowed_tools includes "Skill", and setting_sources=["project"] is set.
--dangerously-skip-permissions cannot be used with root/sudo privilegesSomething switched to bypassPermissions while running as root. Restore permission_mode="dontAsk" and the non-root user.
Permission denied when the skill writesThe directory is missing from {{NONROOT_EXTRA_DIRS}}, so user claude does not own it.
JSON message exceeded maximum buffer sizeA message passed the SDK's 1 MiB framing limit. Set CLAUDE_AGENT_MAX_BUFFER_BYTES.
A Run used N turns (max_turns=50) warning that says approaching capRaise CLAUDE_AGENT_MAX_TURNS.
Error: assistant message error: authentication_failed (or billing_error, rate_limit)Credentials, billing, or quota. Run tests/test_foundry_direct.py to isolate it.
Error: agent completed but produced no text responseLook for an earlier AssistantMessage error or a ResultMessage flagged is_error=True line in the logs.
401 from FoundryRun tests/test_foundry_direct.py, then test_anthropic_sdk_foundry.py, to find which layer fails.
Phase 1 fails with Claude Code returned an error resultRun tests/debug_sdk.py for the full message dump. Check the SDK is at least 0.2.138.
Tokens always report 0Code reads flat input_tokens attributes that do not exist. Read ResultMessage.model_usage.
AMC prices the run at the default ratestep_completed has no model. Pass it, with cached_input_tokens.
A failed run shows zero cost in AMCset_step_tokens and set_cost were not called before re-raising.
Prompt tokens are much higher than the job needstools= is unset, so the full Claude Code toolset is defined in every prompt. Set it to the base set.

Last updated 2026-10-21