Documentation Index
Fetch the complete documentation index at: https://docs.usezombie.com/llms.txt
Use this file to discover all available pages before exploring further.
A zombie that’s misbehaving falls into one of six failure shapes. Find the symptom you’re seeing and follow the diagnostic chain.
Decision tree
| Symptom | Most likely cause | Start here |
|---|
zombiectl install --from exits non-zero | Frontmatter validation failed | §1 Install rejected |
| Upstream says it sent the webhook, zombie didn’t wake | Signature mismatch or wrong URL | §2 Webhook delivered but zombie silent |
| Zombie woke, stage failed before producing output | Credential, network, or tool error | §3 Stage opens then fails |
| Stage produces a result but it’s wrong | SKILL.md prose or memory issue | §4 Stage runs but output is wrong |
Stage terminates with budget_breach | daily_dollars / monthly_dollars ceiling hit | §5 Budget breach |
zombiectl itself is broken (auth, network) | Local config or platform reachability | §6 zombiectl can’t reach the platform |
1. Install rejected
zombiectl install --from <path> exited with code 2. The platform parsed your SKILL.md + TRIGGER.md and rejected them.
zombiectl install --from ./my-zombie --json 2>&1 | tail -5
The --json output carries the wire error code:
| Wire code | Cause | Fix |
|---|
UZ-ZMB-008 | TRIGGER.md config_json fails schema validation | Re-read Authoring §x-usezombie: subkeys. Common: a runtime key (tools, credentials, network) at the top level instead of nested under x-usezombie:. |
UZ-ZMB-011 | SKILL.md and TRIGGER.md disagree on top-level name: | Make both files’ name: value identical. |
UZ-VAULT-001 | Credential data body is empty / not a JSON object | The error is from a prior credential add call, not from install itself. Re-run zombiectl credential add <name> --data=@- with a non-empty JSON object. |
For other codes, check Error codes and grep for the UZ- prefix.
Local validation tip: the parser the platform uses is the same one zombiectl install --from runs — there’s no separate lint command. To catch schema errors before committing, run zombiectl install --from <path> --json and read the structured error output. Note the call still uploads on success; there is no --validate-only flag.
2. Webhook delivered but zombie silent
The upstream provider says it fired the webhook, your activity stream shows nothing.
Diagnostic
# All webhook-actor events in the last hour, including rejected ones
zombiectl events <zombie_id> --actor 'webhook:*' --since 1h --json
Three things to look for in the output:
| Pattern | Meaning |
|---|
| Zero events in the window | Request never reached the platform (DNS, firewall, wrong URL on the upstream side). |
| Events with rejection metadata, not stage opens | Signature verification failed. |
Events but actor: webhook:unknown | Source label is missing or the signature block in TRIGGER.md doesn’t match the upstream’s actual headers. |
Wire codes returned to the upstream
If the upstream itself shows a non-2xx response, the body carries one of:
| Wire code | HTTP | What to check |
|---|
UZ-WH-001 | 404 | URL is wrong. The path is https://api.usezombie.com/v1/webhooks/{zombie_id} — verify the ID matches zombiectl status. |
UZ-WH-002 | 400 | Request body is malformed JSON or empty. |
UZ-WH-003 | 403 | Zombie is paused or killed. zombiectl status will show the state; re-install with zombiectl install --from <path>. |
UZ-WH-010 | 401 | HMAC signature verification failed. The shared secret in your vault doesn’t match the one configured at the upstream. Rotate per Quickstart → Wire the GitHub webhook. |
UZ-WH-011 | 401 | Replay-window violation — request timestamp is older than 5 minutes. Sender clock skew is the usual culprit. |
UZ-WH-020 | 401 | No webhook credential configured for this zombie’s source. The secret_ref in TRIGGER.md either isn’t set or points at a vault key that doesn’t exist. Run zombiectl credential list to confirm; add with zombiectl credential add <source> --data=@-. |
UZ-WH-030 | 413 | Payload exceeds the 1 MiB ingest limit. The upstream is sending too much; filter or trim the event body before forwarding. |
Common signature config mistakes
# WRONG — secret_ref references a vault key that doesn't exist
signature:
secret_ref: github_secret # but you ran: zombiectl credential add github
# ^^^^^^ — name is "github", not "github_secret"
# RIGHT
signature:
secret_ref: github
For first-class providers (github, slack, linear), don’t set header and prefix manually — the registry fills those. See Webhooks → Natively normalized providers.
3. Stage opens then fails
The webhook landed and a stage opened, but it terminated before producing output. The activity stream shows the stage, then an error event.
Diagnostic
zombiectl events <zombie_id> --since 1h --json | jq 'select(.error)'
| Wire code | Cause | Fix |
|---|
UZ-ZMB-003 | A required vault credential is absent | The credential name in TRIGGER.md credentials: doesn’t exist in the workspace vault. zombiectl credential list to confirm; zombiectl credential add <name> --data=@- to add. |
UZ-ZMB-002 | Agent timeout | The model didn’t return within the per-event ceiling. Often a sign the prompt is too large or the model is overwhelmed. Tighten SKILL.md or check tool_window in Context lifecycle. |
UZ-MEM-003 | Memory backend unavailable | Transient. Re-trigger; if persistent, file an issue. |
UZ-MEM-001 | Memory scope denied | The agent tried to read another zombie’s memory. Check the key derivation in SKILL.md — keys are zombie-scoped. |
Tool-related failures don’t surface as wire codes. When a tools: entry has a typo, the executor logs UZ-TOOL-005 at warn level and silently skips it. When the agent tries to invoke a tool that isn’t in its resolved set, NullClaw returns a “no such tool” message in the activity stream rather than emitting UZ-TOOL-004 to a caller. Both UZ-TOOL-* codes exist in the registry (see Error codes → Tool) but in v2 today the diagnostic signal is the activity-stream entry, not a wire response. Audit zombiectl logs <zombie_id> for the actual error text. See Tools catalogue → Validation.
Network allowlist drops
If the agent calls http_request against a host not in network.allow:, the call fails silently from the agent’s perspective (the tool returns an error, the agent reasons about it). The drop appears in the activity stream as a tool-error event with the blocked hostname. Add the host to network.allow: in TRIGGER.md and re-install.
4. Stage runs but output is wrong
The hardest class of failure. Stage exits cleanly, the diagnosis posts to Slack, but the diagnosis is wrong, off-topic, or omits something it should have said.
Diagnostic
# Full event with the agent's tool calls and reasoning trail
zombiectl events <zombie_id> --since 30m --json | jq 'select(.actor | startswith("webhook:") or startswith("steer:"))'
The model’s tool-call trail tells you what it actually did. Compare against what your SKILL.md told it to do:
| Symptom | Likely cause |
|---|
| Agent skipped a step you specified | Step is unclear, ambiguous, or buried mid-paragraph. Move it to a numbered list at the top. |
| Agent called the wrong endpoint | SKILL.md named the endpoint without context. Add the full URL or the credential name explicitly. |
| Agent hallucinated a value | Source data wasn’t in the event payload or a memory recall. Don’t ask the agent to invent — surface every input explicitly. |
| Agent re-asked for info you already gave it | memory_recall isn’t being called at the start of the stage. Audit your SKILL.md — recall must happen before reasoning. See Memory. |
| Agent posted twice | Webhook delivery is at-least-once. Add a dedupe step using the upstream event_id in memory_recall/memory_store. |
Iterating on prose
SKILL.md is a prompt. The fastest debug loop is zombiectl steer:
zombiectl steer <zombie_id> "<the same input that triggered the bug>"
Edit SKILL.md, zombiectl install --from ., re-steer. The next event uses the new prose — no redeploy.
5. Budget breach
Stage terminated with UZ-ZMB-001. The daily_dollars or monthly_dollars ceiling in TRIGGER.md was hit.
zombiectl status --json | jq '.[] | select(.zombie_id == "<id>") | {state, budget}'
Two layers of cap exist independently:
- Per-zombie (
TRIGGER.md budget.daily_dollars / monthly_dollars) — terminates this zombie’s stages until the rolling window resets. Raise the value, re-install.
- Tenant wallet — every workspace’s stages debit the same pool. When it hits zero, all stages across all workspaces stop. Top up at
app.usezombie.com/billing. See Billing → Budgets.
If you’re hitting the per-zombie cap repeatedly on legitimate traffic, the zombie’s per-stage cost is higher than you sized for. Audit the activity stream for unusually long stages (high tokens or wall_ms fields), and consider tightening SKILL.md or splitting the work across multiple smaller zombies.
Anything that affects every command — login fails, status returns errors, install 401s.
Diagnostic
Three checks run; all must pass:
| Check | Failure means |
|---|
server_reachable | API is unreachable from your machine. Check your network. The base URL is https://api.usezombie.com (override with --api or ZOMBIE_API_URL). |
workspace_selected | Local config has no current_workspace_id. Run zombiectl workspace add [name] (creates + activates) or workspace use <id> (activates an existing one). |
workspace_binding_valid | Auth token doesn’t have access to the selected workspace. Either the token expired (re-run zombiectl login) or the workspace was deleted on the server. |
Pass --json for the structured envelope: { ok: bool, api_url: string, checks: [{ name, ok, detail }] }.
Auth resolution order
If zombiectl keeps acting unauthenticated, your token might be coming from somewhere unexpected. Resolution order, highest priority first:
--token <value> flag
ZOMBIE_TOKEN environment variable
- Stored credentials at
~/.config/zombiectl/credentials (written by zombiectl login)
Unset ZOMBIE_TOKEN if you’ve been running CI scripts that exported it; otherwise it overrides whatever zombiectl login wrote.
When to escalate
Two paths, depending on whether you want a fix or a faster sanity-check.
Fast: ask in Discord. Best for “is this a known issue?”, “is this expected?”, or anything where you need a human eye in minutes rather than hours. Design partners and the core team hang out there.
Durable: file an issue at github.com/usezombie/usezombie/issues. Best when the problem is reproducible, blocks shipping, or hits any of:
- Diagnostic returns no error but the symptom persists across multiple triggers.
- A
UZ-INTERNAL-* or UZ-AUTH-004 (auth service unavailable) keeps firing.
zombiectl doctor passes but operations still fail.
Either way, include the request_id from the --json error envelope, the wire code, and a recent timestamp — those uniquely identify the request server-side.
See also