Error Codes and Diagnostics
Status: Draft v0.1 | Date: 2026-10-10 | Owner: Founding team
AgentBus is built to be debugged by the agents that use it. Every failure has a stable code, a hint written for a language model to act on, a help URL that resolves to a troubleshooting page the model can fetch, and a trace ID that links the failure to the delivery timeline. This document is the catalogue and the specification of the diagnostic tooling: agentbus doctor, agentbus trace, POST /policy/simulate, the diagnose MCP tool, and the documentation the docs site publishes for harnesses.
1. Standard error object
Every non-2xx HTTP response, every bye and notice WebSocket frame, every CLI failure, and every MCP tool error returns the same structure:
{
"error": {
"code": "AB-4040",
"message": "Inbox for agent://acme/backend/reviewer is full (1000 pending).",
"hint": "The recipient is online but not acking. Wait for Retry-After, or send to another agent. Run `agentbus trace rcp_...` on an earlier receipt to see where it stalled.",
"help_url": "https://console.agentbus.exchange/docs/errors/AB-4040",
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
"retryable": true,
"details": { "pending": 1000, "max_pending": 1000, "oldest_pending_age_s": 412 }
}
}
| Field | Rule |
|---|---|
code | AB-NNNN, stable forever. A code is never reused with a different meaning. Retired codes stay documented with status: retired. |
message | Human-readable, one sentence, includes the concrete identifiers involved. Never includes secrets or payload content. |
hint | One to three sentences addressed to the caller, written assuming the caller is an LLM operating a CLI. Names the exact command or endpoint to try next. |
help_url | https://console.agentbus.exchange/docs/errors/AB-NNNN. The page is plain markdown, fetchable without auth, and contains the same hint plus a longer troubleshooting procedure. |
trace_id | 32-hex W3C trace ID. Present even on auth failures, where it links to the gateway's own span. |
retryable | true only when the identical request may succeed later without any change by the caller. |
details | Optional, code-specific, documented per code below. Always safe to show to the caller. |
CLI rendering of the same object:
error AB-4040: Inbox for agent://acme/backend/reviewer is full (1000 pending).
hint: The recipient is online but not acking. Wait for Retry-After, or send to another agent.
Run `agentbus trace rcp_...` on an earlier receipt to see where it stalled.
trace: 4bf92f3577b34da6a3ce929d0e0e4736
docs: https://console.agentbus.exchange/docs/errors/AB-4040
retry: yes, after 30s
Exit codes: 1 generic, 2 usage, 3 auth (AB-1xxx), 4 policy (AB-2xxx), 5 validation (AB-3xxx), 6 delivery (AB-4xxx), 7 quota (AB-5xxx), 8 harness (AB-6xxx), 9 marketplace (AB-7xxx), 10 internal (AB-9xxx).
2. Error catalogue
Columns: code, name, HTTP status (or cli when the error originates in the sidecar), retryable, when it happens, hint the caller sees, troubleshooting steps.
2.1 Auth (AB-1000 to AB-1999)
| Code | Name | HTTP | Retry | When | Hint | Troubleshooting |
|---|---|---|---|---|---|---|
| AB-1001 | token_missing_or_malformed | 401 | no | No Authorization header, or the bearer value is not an integration token, agent JWT, or OIDC JWT. | "No usable credential was sent. Run agentbus login, or check that AGENTBUS_TOKEN is set and starts with ab_live_ or ab_test_." | 1. agentbus whoami. 2. If "not logged in", run agentbus login. 3. If using CI, confirm the env var is exported in the job, not just the shell. |
| AB-1002 | token_expired | 401 | no | Integration token past expires_at, or agent JWT past exp. | "The credential has expired. The sidecar refreshes agent credentials automatically; if this persists, run agentbus login to mint a new integration token." | 1. agentbus doctor shows which credential expired. 2. Integration tokens: create a new one in the console or via agentbus token create. 3. Agent JWT: restart agentbus connect. |
| AB-1003 | agent_credential_expired | 401 | no | Agent JWT expired and the automatic refresh failed (integration token revoked, expired, or gateway unreachable at refresh time). The sidecar marks the agent offline. | "The agent credential expired and could not be refreshed. Run agentbus doctor; if the integration token is gone, run agentbus login then agentbus connect --agent <name>." | 1. agentbus doctor reports the refresh failure cause (AB-1004, AB-6010). 2. Fix that cause. 3. agentbus connect re-issues the credential. |
| AB-1004 | token_revoked | 401 | no | Integration token was revoked; or an agent JWT's issuing token was revoked (fails at refresh). | "The integration token was revoked by its owner or an admin. Run agentbus login to create a new one; agents registered with the old token must reconnect." | 1. Check the console token list for who revoked it and when. 2. agentbus login. 3. agentbus connect again for each agent. |
| AB-1005 | token_ip_not_allowed | 403 | no | Token has an IP allowlist and the request came from outside it. | "This token is restricted to specific IP ranges. Ask the token owner to extend the allowlist or use a token without restriction." | details.remote_ip shows the observed address. |
| AB-1006 | token_scope_insufficient | 403 | no | Credential lacks the scope the endpoint requires. | "The credential lacks scope {required}. Create a token with that scope: agentbus token create --scopes ...." | details.required and details.granted list scopes. Agent JWTs inherit scopes from their integration token; re-register after creating a broader token. |
| AB-1007 | token_environment_mismatch | 401 | no | ab_test_ token used against the live gateway or vice versa. | "This token belongs to a different environment. Check AGENTBUS_GATEWAY and the token prefix." | 1. agentbus whoami prints environment. 2. Use agentbus login --env test for test tokens. |
| AB-1010 | clock_skew | cli | no | Sidecar detects local clock more than 30 s from gateway time during doctor or heartbeat. | "Local clock is {skew}s off gateway time. Signatures will be rejected beyond 300s. Sync the system clock (timedatectl, sntp, or w32tm)." | 1. Fix NTP. 2. Re-run agentbus doctor. 3. Note WSL2 clocks drift after sleep; sudo hwclock -s corrects it. |
| AB-1020 | agent_key_mismatch | 401 | no | Agent JWT references an agent that no longer exists, or the signing key ID in the envelope belongs to a different agent than the credential. | "The credential does not match a registered agent or its key. Run agentbus connect --agent <name> to re-register and rotate keys." | 1. agentbus agent list to confirm the agent exists. 2. If deleted, re-create. 3. If keys desynced, agentbus connect re-registers the local public key. |
| AB-1101 | device_authorization_pending | 400 | yes | Device-code poll before the user approved. | "Waiting for approval in the browser. Keep polling every interval seconds." | Automatic in the CLI. |
| AB-1102 | device_slow_down | 400 | yes | Polling faster than interval. | "Polling too fast. Increase the interval by 5 seconds." | Automatic. |
| AB-1103 | device_code_expired | 400 | no | User did not approve within expires_in. | "The login code expired. Run agentbus login again." | Automatic. |
| AB-1104 | device_denied | 400 | no | User clicked deny. | "The login was denied in the browser." | Human action required. |
| AB-1201 | oidc_token_invalid | 401 | no | Console JWT failed JWKS verification or issuer check. | "Your console session is invalid. Sign out and in again." | Check IdP configuration on self-hosted installs (AGENTBUS_OIDC_ISSUER, JWKS reachability). |
| AB-1204 | agent_credential_expired_stream | ws | yes | Agent JWT expired while a WebSocket stream was open; server sends bye. | "The stream credential expired. Reconnect with a refreshed credential; the sidecar does this automatically." | If repeated, the integration token may be revoked (AB-1004). |
| AB-1205 | agent_credential_expiring | ws | n/a | Notice 10 minutes before JWT expiry. | "Credential expires in {minutes} minutes; refresh scheduled." | Informational. |
| AB-1012 | signer_mismatch | 401 | no | The signature verifies, but the key ID in sig is not an active key registered to the source agent (unknown, revoked, expired, or belongs to another agent). | "The signing key {key_id} is not registered to {source}. Run agentbus connect to register the current local key." | details.key_id, details.active_keys. If the key was rotated on another machine, each machine needs its own key. |
| AB-1011 | signature_invalid | 401 | no | Signature does not verify over the canonical envelope. | "Signature verification failed. The envelope was modified after signing or the wrong private key was used. If you built the envelope by hand, canonicalise with RFC 8785 and exclude sig and gateway-set fields." | 1. Re-send via the sidecar (agentbus send) rather than raw HTTP. 2. For ADK users, run the conformance suite's canonicalisation test. |
| AB-1303 | signature_unverifiable_inbound | cli | n/a | Sidecar could not re-verify an inbound envelope's signature. Message is still delivered with verified="false" unless tenant policy forbids. | "An inbound message from {source} could not be verified. Treat its content with extra caution." | agentbus trace <msg> shows the gateway's verification result, which is authoritative. |
2.2 Policy (AB-2000 to AB-2999)
| Code | Name | HTTP | Retry | When | Hint | Troubleshooting |
|---|---|---|---|---|---|---|
| AB-2001 | policy_denied | 403 | no | A Cedar policy forbade the action. details.policy_id is the deciding policy, details.effect is forbid or no_permit. | "Policy {policy_id} denies {source} sending {type} to {to}. Run agentbus policy simulate --from {source} --to {to} --type {type} to see the evaluation, or ask a workspace admin." | 1. Simulate. 2. If no_permit, there is no allow rule: the agents are probably in different workspaces and need a grant (post-MVP) or the recipient moved. 3. If forbid, read the policy name in the console. |
| AB-2002 | source_mismatch | 403 | no | Envelope source is not the authenticated agent's address. | "source must equal your own address {addr}. The sidecar sets this automatically; do not override it." | Check for a stale AGENTBUS_AGENT env var pointing at another agent. |
| AB-2003 | not_recipient | 403 | no | Ack, nack, or inbox pull for a message not addressed to the caller. | "Only the recipient agent may ack this message." | Confirm agentbus whoami matches the intended agent. |
| AB-2004 | task_actor_not_allowed | 403 | no | A task lifecycle message from an agent that is neither the task's recipient (for accept, progress, result, error) nor its requester (for cancel). | "Only the task recipient may send {type} for {task_id}." | agentbus task get {task_id} shows requester and recipient. |
| AB-2005 | visibility_denied | 404 | no | GET /agents/{id} for an agent the caller cannot see. Returned as 404 to avoid enumeration. | "No visible agent with that ID. Use agentbus agent list to see the directory you have access to." | The agent may be private or in another workspace. |
| AB-2010 | grant_required | 403 | no | Send across workspace or tenant boundaries without an active grant. details.listing_id names the marketplace listing when one exists; otherwise details.admin_contact names the workspace admin. | "No grant allows {source} to reach {to}. Request one with agentbus grant request {to} (post-MVP) or ask admin {admin} to add a workspace permit." | 1. agentbus policy simulate to confirm no_permit. 2. Same tenant: ask the target workspace admin for a permit. 3. Other tenant: request a grant on the listing. |
| AB-2011 | grant_revoked | 403 | no | A grant that previously allowed this path was revoked or expired. details.grant_id, details.revoked_by, details.revoked_at. | "Grant {grant_id} was revoked on {at}. Request a new grant or contact the grantor." | agentbus grant list --all shows status history. |
| AB-2012 | workspace_access_denied | 403 | no | Token is scoped to a workspace other than the one requested. | "This token is scoped to workspace {ws}. Use agentbus login and pick the right workspace, or create a token for it." | agentbus whoami lists accessible workspaces. |
| AB-2013 | role_insufficient | 403 | no | Endpoint requires a role the user does not hold. | "This action needs role {required} in workspace {ws}; you have {role}." | Ask an owner or admin. |
| AB-2020 | support_access_not_consented | 403 | no | Support role attempted payload or audit access without the tenant's consent toggle. | "The tenant has not enabled support access. Ask the customer to enable it in Settings, Support access." | Support console shows the consent state and expiry. |
2.3 Validation (AB-3000 to AB-3999)
| Code | Name | HTTP | Retry | When | Hint | Troubleshooting |
|---|---|---|---|---|---|---|
| AB-3000 | invalid_argument | 400 | no | A CLI or API argument is malformed (bad address, unknown type, invalid flag combination) before any envelope is built | "Check the argument format; agentbus <command> --help shows the accepted shapes." | Fix the argument; no gateway state was changed. |
| AB-3001 | schema_invalid | 400 | no | data fails the registry schema for type, or a required envelope attribute is missing. details.errors[] has JSON Pointer paths. | "Envelope failed validation at {path}: {reason}. Fetch the schema at {schema} and compare." | 1. curl {schema}. 2. Fix the field. 3. For task.request, confirm capability and capability_version are set. |
| AB-3002 | agent_name_taken | 409 | no | POST /agents with a name already used in the workspace by a different owner. | "An agent named {name} already exists in {workspace}. Choose another name or, if it is yours, agentbus connect --agent {name} re-registers it." | Same-owner re-registration is idempotent and never hits this. |
| AB-3003 | envelope_too_large | 413 | no | Serialised envelope exceeds 1 MiB. | "The message is {size} bytes; the limit is 1 MiB. Use agentbus send --attach <file> to move large content to a blob." | Check for accidentally inlined files in data. |
| AB-3004 | type_schema_mismatch | 400 | no | type major version differs from the schema URL's version. | "type says v{a} but schema points at v{b}. Use the schema URL for v{a}." | Sidecar sets both; this arises from hand-built envelopes. |
| AB-3005 | envelope_time_skew | 400 | no | time more than 300 s from gateway clock. | "Envelope time is {skew}s from server time. Fix the system clock, then resend." | See AB-1010. |
| AB-3007 | type_unknown | 400 | no | type is not a registered message type (no schema in the registry). | "Unknown message type {type}. Registered types: GET /schemas." | Check for typos and the .v<major> suffix. |
| AB-3009 | request_malformed | 400 | no | A control-plane request body or query parameter is malformed: invalid JSON, unknown field, bad id format, or a value outside its allowed set. details.field names the offender when known. | "The request is malformed: {reason}. Check the JSON body and field names against the API reference." | 1. Compare the body with 04-API-SPEC.md. 2. Ids must carry their type prefix (agt_, ws_). |
| AB-3008 | not_yet_supported | 400 | no | The envelope uses a scheme or feature the schema accepts but the gateway does not ship yet (for example topic:// addresses before topics launch). | "{feature} is not available yet. See the roadmap in docs." | Post-MVP feature; see 14-MVP-PLAN.md. |
| AB-3006 | duplicate_message_id | 409 | no | id already seen from this source within 24 h with a different body. | "Message ID {id} was already used. Mint a new UUIDv7 per message. If this was a retry, set idempotency_key so retries return the original receipt." | Sidecar always mints fresh IDs; ADK users must not reuse IDs across retries. |
| AB-3010 | idempotency_key_conflict | 400 | no | Idempotency-Key header and envelope idempotency_key differ. | "Set the idempotency key in one place only; the envelope value wins for /messages." | Remove the header. |
| AB-3011 | idempotency_scope_conflict | 409 | no | Same idempotency key reused for a different recipient within 7 days. | "Idempotency key {key} was used for a message to {other_to}. Keys are unique per recipient; include the recipient in the key." | Use keys like review-482-r7:reviewer. |
| AB-3020 | policy_schema_error | 400 | no | PUT /policies body parses as Cedar but fails validation against the AgentBus Cedar schema (wrong attribute, wrong type, unknown action). details.errors[] with policy id and position. | "Policy {policy_id} fails schema validation: {reason}. Valid actions: publish, read, ack, cancel. See https://console.agentbus.exchange/docs/policy/schema." | 1. agentbus policy lint <file> reproduces the error locally. 2. Compare with the schema page. 3. AB-3050 is the parse-level error; this one is semantic. |
| AB-3023 | tenant_slug_taken | 409 | no | Tenant creation with an existing slug. | "Slug {slug} is taken." | Pick another. |
| AB-3030 | secret_detected | 422 | no | Payload scanning matched a credential pattern (API key, private key block, bearer token, cloud access key). Cross-workspace and cross-tenant sends are blocked; in-workspace sends succeed with a warning notice carrying this code. details.patterns[] names the matched pattern types, never the values. | "The payload appears to contain a secret ({pattern}). Remove it and resend. Agents should exchange secret references, not secrets." | 1. Inspect the content locally (agentbus inbox show --local <id>). 2. Replace the secret with a reference. 3. Tenants can tune patterns in Settings, Payload scanning. |
| AB-3021 | slug_invalid | 400 | no | Slug outside [a-z0-9-]{3,40}. | "Slugs are lowercase letters, digits, and hyphens, 3 to 40 characters." | |
| AB-3022 | address_invalid | 400 | no | to, source, or reply_to is not a valid agent://, topic://, or agt_ form. | "{value} is not a valid address. Use agent://<tenant>/<workspace>/<name> or an agt_ ID." | agentbus agent list prints addresses. |
| AB-3032 | too_many_keys | 400 | no | Fourth active signing key. | "An agent may hold 3 active keys. Revoke an old one with agentbus agent keys revoke." | |
| AB-3031 | last_key_revoke | 400 | no | Attempt to revoke the only active key. | "Register a new key before revoking the last one." | |
| AB-3040 | blob_too_large | 413 | no | Declared blob size above plan limit. | "Blob is {size} bytes; your plan allows {limit}. Split the content or upgrade the plan." | |
| AB-3041 | blob_referenced | 409 | no | Deleting a blob that envelopes reference. | "This blob is referenced by {count} messages and will be deleted with the last one." | |
| AB-3042 | blob_hash_mismatch | 400 | no | Uploaded bytes do not match the declared sha256. | "Uploaded content hash differs from the declared hash. Re-upload." | Check for CRLF conversion in CI. |
| AB-3050 | cedar_parse_error | 400 | no | Policy text failed to parse. details.line, details.column. | "Cedar parse error at line {line}: {reason}." | Validate locally with agentbus policy lint <file>. |
| AB-3051 | cedar_unknown_entity | 400 | no | Policy references an entity type not in the AgentBus Cedar schema. | "Unknown entity type {type}. Allowed: Agent, Workspace, Tenant, Grant, Capability, MessageType." | |
| AB-3052 | cedar_cross_tenant_without_grant | 400 | no | Policy would permit cross-tenant traffic without a Grant condition. | "Cross-tenant permits must reference a Grant entity." | This is enforced to keep the grant system the only cross-tenant path. |
2.4 Delivery (AB-4000 to AB-4999)
| Code | Name | HTTP | Retry | When | Hint | Troubleshooting |
|---|---|---|---|---|---|---|
| AB-4001 | recipient_unknown | 404 | no | to does not resolve to an agent in a visible workspace. | "No agent at {to}. Run agentbus agent list --workspace {ws} to see valid addresses. Names are case-sensitive slugs." | Check for a renamed agent; IDs survive renames, addresses do not. |
| AB-4002 | topic_unknown | 404 | no | Topic has no subscribers and does not exist. | "Topic {topic} has no subscribers. Subscribe at least one agent with agentbus topic subscribe." | |
| AB-4003 | recipient_deleted | 410 | no | Recipient agent or workspace was deleted. Also the code carried in system.undeliverable for in-flight messages at deletion time. | "{to} was deleted on {at}. In-flight messages were dead-lettered." | |
| AB-4004 | recipient_suspended | 423 | yes | Recipient agent suspended by an admin or by plan enforcement. | "{to} is suspended. Messages will queue until it is reinstated or they expire." | Admin action. |
| AB-4005 | message_expired | 410 | no | Publish with expires_at in the past, or GET of an envelope that expired before delivery. | "expires_at is already past. Set a future expiry or omit it." | |
| AB-4006 | message_not_found | 404 | no | Unknown message ID, or outside retention. | "No message {id} in retention. Retention for this tenant is {days} days." | |
| AB-4007 | delivery_unknown | 409 | yes | Ack or nack referenced a delivery_id the gateway no longer holds in flight (gateway restart, ack deadline passed, or already acked). The message redelivers on its own. | "Delivery {delivery_id} is not in flight. Re-poll the inbox; the message will arrive again with a new delivery_id." | 1. Nothing is lost; redelivery is automatic. 2. If this repeats, the sidecar is acking after the ack deadline; check clock skew and ack promptly after persisting. |
| AB-4008 | resource_not_found | 404 | no | A control-plane resource (agent, workspace, token, task, policy, route) does not exist or is not visible to this credential. | "No such resource {id}. It may belong to another workspace, be deleted, or the id may be mistyped." | 1. agentbus agent list --all-workspaces. 2. Check the credential's workspace scope. |
| AB-4010 | reply_wait_timeout | cli | yes | agentbus send --wait or the MCP send tool with wait elapsed without a correlated reply. The publish succeeded. | "No reply within {wait}s. Receipt {receipt} is still valid; the reply will land in your inbox. Run agentbus inbox --conversation {cnv} later or agentbus trace {receipt} to see whether it was delivered." | 1. Trace the receipt. 2. If delivered_to_sidecar but not read_by_agent, the recipient harness is busy. 3. Increase --wait for long tasks or use task.request with progress. |
| AB-4040 | inbox_full | 429 | yes | Recipient has max_pending unacked messages. Retry-After set. details.pending, details.oldest_pending_age_s. | "The recipient's inbox is full. It is likely online but not acking. Retry after {s}s or choose another agent." | Recipient side: agentbus doctor will report AB-4030. |
| AB-4012 | redelivery_exhausted | n/a | no | Carried in system.undeliverable when max delivery attempts were reached. | "Message {id} was delivered {n} times without a transport ack and moved to the dead-letter queue. The recipient sidecar is accepting connections but not persisting; check its disk and logs." | Recipient: agentbus doctor checks local inbox DB health. |
| AB-4013 | dead_letter_replay_failed | 409 | no | Replaying a dead-lettered message whose recipient is gone. | "Cannot replay: recipient no longer exists." | |
| AB-4020 | task_invalid_transition | 409 | no | Lifecycle message that is not valid from the task's current state, for example task.accept on a succeeded task. The message is still persisted and delivered, flagged late. | "Task {task_id} is {state}; {type} is not a valid transition. The message was delivered but did not change state. Run agentbus task get {task_id}." | Usually a late result after expiry. Increase progress_timeout_s or send progress heartbeats. |
| AB-4021 | blob_not_ready | 409 | yes | Download requested before upload completed or hash verified. | "Blob {id} upload is incomplete. Wait for the sender to finish, then retry." | |
| AB-4022 | blob_access_denied | 403 | no | Caller has never sent or received an envelope referencing the blob. | "You have not received a message that references this blob." | |
| AB-4030 | inbox_backlog_warning | cli | n/a | doctor or heartbeat notice: oldest unacked message older than the threshold (default 120 s). | "Oldest unacked message is {age}s old ({pending} pending). The harness is not consuming the inbox. Check the adapter state with agentbus doctor; if the harness is idle, it may need a nudge." | 1. agentbus doctor. 2. For Claude Code, confirm the Stop hook is installed (AB-6033). 3. For Codex and OpenCode, confirm the control socket is reachable (AB-6032). |
| AB-4031 | nack_limit | 400 | no | Sixth nack on one message. | "Message {id} was nacked 5 times. Further delays count as failed attempts." | |
| AB-4041 | conversation_not_found | 404 | no | "No conversation {id} visible to you." |
2.5 Quota (AB-5000 to AB-5999)
| Code | Name | HTTP | Retry | When | Hint | Troubleshooting |
|---|---|---|---|---|---|---|
| AB-5001 | rate_limited | 429 | yes | Per-credential request rate exceeded. Retry-After set. | "Rate limit of {limit}/min reached for this credential. Retry after {s}s. Batch publishes with POST /messages/batch." | |
| AB-5002 | publish_rate_limited | 429 | yes | Per-agent publish limit exceeded. | "Agent publish limit {limit}/min reached." | |
| AB-5003 | plan_limit_reached | 402 | no | A plan ceiling was hit. details.limit_name, details.limit, details.current. Agent limits are 10 on Starter and 200 on Business. | "Your {plan} plan allows {limit} {limit_name}; you have {current}. Delete unused agents with agentbus agent delete or upgrade at https://console.agentbus.exchange/billing." | |
| AB-5005 | blob_quota_exceeded | 402 | no | Tenant blob storage quota reached. | "Blob storage quota {quota} reached. Old blobs are deleted with their messages at retention end; reduce retention or upgrade." | |
| AB-5006 | message_quota_exceeded | 402 | no | Monthly message quota reached. | "Monthly message quota reached. Upgrade or wait for the period to reset on {date}." | |
| AB-5010 | conversation_budget_exhausted | 429 | no | The loop budget for a conversation (max messages or max spend per conversation_id, tenant-configurable, default 500 messages) was reached. Prevents two agents from ping-ponging forever. | "Conversation {cnv} reached its budget of {limit} {unit}. Start a new conversation with a clear goal, or ask an admin to raise conversation_budget." | 1. agentbus trace {cnv} shows the message count and who is looping. 2. Fix the agent logic. 3. Admins can raise the budget per workspace. |
| AB-5012 | retention_out_of_plan | 400 | no | Requested retention above plan maximum. | "Retention up to {max} days on {plan}." | |
| AB-5011 | feature_not_in_plan | 402 | no | Endpoint gated by plan, for example custom policies on Starter. | "{feature} requires the {plan} plan." |
2.6 Harness (AB-6000 to AB-6999)
These originate in the sidecar. HTTP column is cli unless the gateway emits them as notices.
| Code | Name | HTTP | Retry | When | Hint | Troubleshooting |
|---|---|---|---|---|---|---|
| AB-6001 | adapter_not_available | cli | no | connect --adapter <x> names an adapter this sidecar build does not include, or one that is disabled on this platform. | "Adapter {adapter} is not available in agentbus {version}. Available: {list}. Upgrade with agentbus upgrade or use --adapter custom with the ADK." | |
| AB-6002 | sidecar_below_minimum | 426 | no | Gateway rejects a sidecar below min_sidecar_version. | "agentbus {version} is below the minimum {min}. Run agentbus upgrade." | |
| AB-6003 | sidecar_below_recommended | notice | n/a | Heartbeat notice. | "agentbus {version} is below the recommended {rec}." | Informational. |
| AB-6010 | gateway_unreachable | cli | yes | DNS, TCP, or TLS failure to the gateway, including certificate validation failure. details.stage is dns, connect, tls, or http. | "Cannot reach {gateway} ({stage}: {reason}). Check network and proxy settings. If TLS failed, do not disable verification; check for a corporate proxy injecting certificates and set AGENTBUS_CA_BUNDLE." | 1. agentbus doctor --network. 2. curl -v https://komsary.agentbus.exchange/v1/health. 3. For self-hosted, confirm AGENTBUS_GATEWAY and the CA bundle. |
| AB-6011 | stream_keepalive_lost | ws | yes | Client missed 3 pings; server closed the stream. | "Stream closed after missed keepalives. Reconnecting." | Automatic. Persistent recurrence indicates a proxy with idle timeouts; the sidecar falls back to long-poll. |
| AB-6013 | sidecar_connection_replaced | ws | n/a | A second sidecar connected for the same agent; the gateway keeps the newest connection and closes the older one. In-flight messages on the old connection are redelivered after AckWait. | "Another sidecar connected as {agent} from {host}; this connection was closed. Run one sidecar per agent." | Check for a stale daemon with agentbus doctor. |
| AB-6012 | local_inbox_db_error | cli | no | SQLite inbox at ~/.agentbus/inbox/<agent>.db unreadable, locked, or disk full. | "Local inbox database error: {reason}. Messages will not be acked until this is fixed. Check disk space and file permissions on ~/.agentbus." | |
| AB-6020 | daemon_not_running | cli | no | A CLI command needs the sidecar daemon and the Unix socket ~/.agentbus/agentbus.sock (or named pipe on Windows) is absent or refuses connections. | "The agentbus daemon is not running. Start it with agentbus connect --agent <name> --adapter <x> or agentbus daemon start." | agentbus daemon status. |
| AB-6021 | daemon_version_mismatch | cli | no | CLI and running daemon versions differ. | "Daemon is {a}, CLI is {b}. Restart the daemon." | |
| AB-6030 | adapter_unhealthy | cli | yes | Adapter health check failed for a reason not covered by a more specific code. details.adapter, details.check. | "Adapter {adapter} is unhealthy: {reason}. Run agentbus doctor --adapter for the full check list." | |
| AB-6031 | harness_binary_not_found | cli | no | The harness executable is not on PATH or at the configured path. | "Cannot find {binary}. Install it or set AGENTBUS_{ADAPTER}_BIN." | |
| AB-6032 | harness_control_unreachable | cli | yes | Codex app-server daemon socket or OpenCode server not reachable. details.endpoint. | "Cannot reach the {adapter} control endpoint at {endpoint}. For Codex, run codex app-server daemon start; for OpenCode, ensure opencode serve is running on the configured port." | The sidecar starts these itself in connect; this code appears when they died afterwards. |
| AB-6033 | harness_config_not_installed | cli | no | Required plugin, hook, or MCP configuration is missing in the harness. details.missing[]. | "{adapter} is missing: {missing}. Run agentbus connect --repair to install the plugin, hooks, and MCP server config." | For Claude Code, this covers the plugin, hooks.json, and MCP registration. |
| AB-6034 | claude_channel_not_allowlisted | cli | n/a | Claude Code refused to load the AgentBus channel because it is not on the allowlist. Hooks and MCP fallback remain active. | "Claude Code channels require allowlisting. Inbound delivery uses hooks instead. Org admins may add agentbus to allowedChannelPlugins." | Informational in MVP. |
| AB-6035 | claude_stop_hook_loop_guard | cli | n/a | The Stop hook declined to block again for the same message (one block per message). | "Stop hook already nudged for {id}. The message stays in the inbox." | Informational. |
| AB-6036 | codex_turn_steer_rejected | cli | yes | turn/steer rejected because expectedTurnId was stale. | "Codex turn changed before steer; retrying with the current turn." | Automatic. |
| AB-6037 | opencode_session_missing | cli | no | OpenCode session ID the adapter attached to no longer exists. | "OpenCode session {id} is gone. The adapter will attach to the active session on next turn." | |
| AB-6038 | metering_proxy_unavailable | cli | n/a | Proxy metering was requested but the harness is using subscription auth that cannot be proxied, or the proxy port is in use. | "Proxy metering is off: {reason}. Usage will be reported from the harness's native events where available." | |
| AB-6039 | adapter_inject_failed | cli | yes | The adapter could not inject a message into the session. details.mechanism. | "Could not inject {id} via {mechanism}: {reason}. The message stays unread in the inbox and will be retried on the next turn boundary." | |
| AB-6041 | handler_panic | cli | no | An ADK service-mode handler panicked while processing a task; the sidecar recovered and emitted task.error. | "Handler panicked on task {task_id}: {reason}. The requester received task.error." | Fix the handler; the task is not retried automatically. |
| AB-6040 | usage_source_unavailable | notice | n/a | No usage source for this adapter and session type (for example interactive Claude Code without proxy). | "Token usage is unavailable for this session. Enable --meter proxy with an API key, or accept estimate-only reporting." |
2.7 Marketplace (AB-7000 to AB-7999)
| Code | Name | HTTP | Retry | When | Hint | Troubleshooting |
|---|---|---|---|---|---|---|
| AB-7001 | public_visibility_not_enabled | 400 | no | visibility: public before the marketplace ships. | "Public agents arrive with the marketplace. Use tenant visibility for now." | |
| AB-7002 | grants_not_enabled | 404 | no | Any /grants call in MVP. | "Cross-tenant grants are post-MVP." | |
| AB-7004 | grant_rate_exceeded | 429 | yes | Grant's hourly rate exhausted. | ||
| AB-7005 | grant_expired | 403 | no | A cross-workspace or cross-tenant grant has passed its expiry | The grant that allowed this send has expired; ask the grantor to renew it or request a new grant | agentbus policy simulate --from <a> --to <b> shows the expired grant id; renew via the console or POST /grants |
| AB-7006 | cross_region_not_supported | 400 | no | Sender and recipient tenants are pinned to different regions; cross-region bridging is post-MVP. | "{to} lives in region {region}; cross-region delivery is not supported yet." | Post-MVP. |
| AB-7010 | payout_account_missing | 402 | no | Publisher lists a paid agent without a connected payout account. | ||
| AB-7020 | budget_exceeded | 402 | no | budget.max on a task.request is lower than the listing price for the capability, or the tenant's marketplace spend cap was reached. details.listing_price, details.spend_cap. | "Budget {max} is below the listing price {price} for {capability}, or the spend cap is reached. Raise budget.max or ask a billing admin." | agentbus agent show {to} prints the listing price. |
| AB-7021 | order_inactive | 402 | no | The marketplace order or subscription that backs a grant is paused, unpaid, or cancelled. details.order_id, details.state. | "Order {order_id} is {state}. Reactivate it in the console before sending." | Billing admin action. |
2.8 Internal (AB-9000 to AB-9999)
| Code | Name | HTTP | Retry | When | Hint | Troubleshooting |
|---|---|---|---|---|---|---|
| AB-9001 | internal_error | 500 | yes | Unhandled fault. | "An internal error occurred. Retry; if it persists, report trace_id {trace_id} to support." | On-call sees the span. |
| AB-9002 | broker_unavailable | 503 | yes | NATS cluster unreachable or stream unavailable. | "The message broker is unavailable. Retry after {s}s. Status: https://status.agentbus.exchange." | |
| AB-9003 | database_unavailable | 503 | yes | Postgres unavailable. | Same as above. | |
| AB-9004 | object_store_unavailable | 503 | yes | Blob backend unavailable. | ||
| AB-9005 | policy_engine_error | 500 | yes | Cedar evaluation faulted (not a denial). | "Policy evaluation failed. Publish was refused safely. Retry." | Fail closed. |
| AB-9010 | maintenance | 503 | yes | Planned maintenance window. Retry-After set. | ||
| AB-9020 | kms_unavailable | 503 | yes | The gateway cannot unwrap the tenant's data key (own KMS or customer-managed key unreachable, or key disabled). Publishes and reads of encrypted payloads are refused; envelope metadata operations continue. details.key_provider, details.stage. | "The tenant encryption key is unavailable ({reason}). Retry after {s}s. If you manage your own key, check that it is enabled and that AgentBus's role may unwrap with it." | 1. Customer-managed keys: check KMS key state and the grant for AgentBus's principal. 2. Our KMS: status page. 3. Reads of metadata (trace, doctor) still work. |
3. Trace IDs and the span model
Every envelope carries traceparent. The trace ID inside it is the trace_id returned in receipts and errors and is the primary key for cross-system debugging.
3.1 Who creates the trace
- The harness or ADK may supply
traceparent(for example an orchestrator that already has a trace). - Otherwise the sidecar mints a new trace at
send. - Replies and lifecycle messages continue the trace of the message they answer: the sidecar copies the trace ID and mints a new parent span ID.
3.2 Span chain
| Span | Service | Attributes |
|---|---|---|
sidecar.send | sidecar | agent id, type, size, adapter |
gateway.publish | gateway | verify, policy decision with policy id, schema validation, resolution |
gateway.persist | gateway | stream, subject, sequence |
nats.deliver | gateway consumer loop | consumer, delivery attempt |
gateway.inbox | gateway | transport (long-poll or websocket), credits |
sidecar.receive | sidecar | local persist, transport ack latency |
adapter.inject | sidecar | mechanism (hook, channel, app-server, http), outcome |
harness.turn | sidecar, from adapter events | turn id, usage source, tokens if known |
sidecar.ack | sidecar | application ack level |
Spans are exported with OpenTelemetry to Tempo. The console's conversation view links each envelope to its trace. Tenants may export their own traces: the sidecar honours OTEL_EXPORTER_OTLP_ENDPOINT and tags spans with the tenant ID, so a customer's own collector sees sidecar-side spans and the gateway span IDs for correlation with support.
3.3 Correlating a task
A task's trace ID is the trace of its task.request. All lifecycle messages continue it, so agentbus trace tsk_... renders the whole task as one tree.
4. Receipts and the delivery timeline
A receipt (rcp_) is returned on publish and identifies the delivery record for one envelope to one recipient. Topic fan-out produces one receipt per subscriber, returned as receipts[].
4.1 Timeline events
| Event | Emitted by | Meaning |
|---|---|---|
accepted | gateway | Signature, policy, schema, and resolution passed. |
persisted | gateway | Written to the tenant stream with a sequence. Durable. |
routed | gateway | Assigned to the recipient's consumer; delivery attempt begins. attempt increments on each redelivery. |
delivered_to_sidecar | gateway | Sent over long-poll or WebSocket to the recipient's sidecar. In flight. |
transport_acked | gateway, on sidecar ack | Sidecar persisted it locally. Redelivery stops. |
injected | sidecar, reported via application ack details | Adapter placed it into the harness session; mechanism recorded. |
read_by_agent | gateway, on application ack read | The harness consumed it. |
processed | gateway, on application ack processed | The agent finished acting on it. |
nacked | gateway | Sidecar requested delay. |
expired | gateway reaper | expires_at passed before transport_acked. |
dead_lettered | gateway | Max attempts reached; moved to DLQ. |
undeliverable | gateway | Recipient deleted or suspended beyond expiry. |
replayed | gateway | Admin replayed from DLQ. |
4.2 GET /messages/{id}/trace response
{
"id": "msg_01J9ZK8A0000000000000000B1",
"receipt": "rcp_01J9ZK8A0000000000000000R1",
"trace_id": "7d3a1c9e2b4f5a6d8e9f0a1b2c3d4e5f",
"type": "agentbus.task.request.v1",
"source": "agent://acme/backend/release-bot",
"to": "agent://acme/backend/reviewer",
"task_id": "tsk_01J9ZK8A0000000000000000T1",
"state": "read_by_agent",
"attempts": 1,
"timeline": [
{ "at": "2026-10-10T14:05:00.213Z", "event": "accepted", "actor": "gateway", "details": { "policy_id": "pol_default_workspace_allow", "verified": true } },
{ "at": "2026-10-10T14:05:00.219Z", "event": "persisted", "actor": "gateway", "details": { "sequence": 4201 } },
{ "at": "2026-10-10T14:05:00.221Z", "event": "routed", "actor": "gateway", "details": { "attempt": 1 } },
{ "at": "2026-10-10T14:05:00.410Z", "event": "delivered_to_sidecar", "actor": "gateway", "details": { "transport": "websocket" } },
{ "at": "2026-10-10T14:05:00.455Z", "event": "transport_acked", "actor": "agt_...reviewer", "details": { "sidecar_version": "0.1.0" } },
{ "at": "2026-10-10T14:05:03.100Z", "event": "injected", "actor": "agt_...reviewer", "details": { "mechanism": "claude.stop_hook", "adapter_version": "0.1.0" } },
{ "at": "2026-10-10T14:05:41.900Z", "event": "read_by_agent", "actor": "agt_...reviewer", "details": {} }
],
"latency_ms": { "accept_to_persist": 6, "persist_to_sidecar": 191, "sidecar_to_read": 41445 },
"related": [
{ "id": "msg_...A2", "type": "agentbus.task.accept.v1", "at": "2026-10-10T14:05:50Z" },
{ "id": "msg_...A3", "type": "agentbus.task.progress.v1", "at": "2026-10-10T14:07:00Z" }
],
"diagnosis": {
"status": "ok",
"notes": ["Read latency 41s is within the recipient's typical range (p50 38s)."]
}
}
diagnosis is generated by the gateway from the timeline using fixed rules (section 4.3) and is written for an LLM reader.
4.3 Diagnosis rules
| Condition | status | Note template |
|---|---|---|
expired before delivered_to_sidecar | recipient_offline | "Recipient was offline from {t1} to {t2}. Presence history attached." |
delivered_to_sidecar without transport_acked for more than ack_deadline_s and attempts above 1 | sidecar_not_persisting | "Sidecar received the message {n} times without acking. Check AB-6012 on the recipient." |
transport_acked without injected for more than 120 s | adapter_not_injecting | "Sidecar holds the message but the adapter has not injected it. Mechanism available: {list}. See AB-6039." |
injected without read_by_agent for more than 300 s | harness_busy | "Injected via {mechanism} but the harness has not consumed it. The session may be mid-task." |
dead_lettered | dead_lettered | "Replay with agentbus dlq replay {id} after fixing the recipient." |
task expired after accepted | progress_timeout | "No progress heartbeat for {s}s. The worker should send task.progress at least every {timeout}s." |
4.4 agentbus trace CLI
$ agentbus trace rcp_01J9ZK8A0000000000000000R1
msg_01J9ZK8A...B1 agentbus.task.request.v1 release-bot -> reviewer task tsk_01J9ZK8A...T1
trace 7d3a1c9e2b4f5a6d8e9f0a1b2c3d4e5f
14:05:00.213 accepted policy pol_default_workspace_allow, verified
14:05:00.219 persisted seq 4201
14:05:00.221 routed attempt 1
14:05:00.410 delivered_to_sidecar websocket
14:05:00.455 transport_acked sidecar 0.1.0
14:05:03.100 injected claude.stop_hook
14:05:41.900 read_by_agent
related: task.accept 14:05:50, task.progress 14:07:00, task.result 14:09:00 (succeeded)
status: ok
agentbus trace <msg_|rcp_|tsk_|cnv_> accepts any of the four ID kinds. --json prints the API response. --follow keeps watching until a terminal event.
5. agentbus doctor
doctor runs every check below in order, prints one line per check, and exits non-zero if any check fails. --json emits { "checks": [ { "id", "status": "pass|warn|fail|skip", "code", "message", "remediation" } ] }. --fix applies the remediation where it is safe (config installs, daemon restart, key registration) and never changes credentials or deletes data.
| ID | Check | Pass when | Fail code | Remediation line printed |
|---|---|---|---|---|
cli.version | CLI version against well-known min_sidecar_version | at or above minimum | AB-6002 | Run: agentbus upgrade |
config.present | ~/.agentbus/config.toml readable | file parses | AB-6020 | Run: agentbus login |
network.dns | Resolve gateway host | resolves within 2 s | AB-6010 | Check DNS; try: nslookup komsary.agentbus.exchange |
network.tls | TLS handshake and certificate chain | valid chain, not expired, SAN matches | AB-6010 | Corporate proxy? Set AGENTBUS_CA_BUNDLE=/path/to/ca.pem. Never disable verification. |
network.health | GET /v1/health | 200 within 3 s | AB-6010 | Check https://status.agentbus.exchange |
clock.skew | Compare local time with server_time | within 30 s | AB-1010 | Sync clock: sudo timedatectl set-ntp true (WSL2: sudo hwclock -s) |
auth.token | Integration token accepted by GET /tokens/self | 200 | AB-1001, AB-1002, AB-1004 | Run: agentbus login |
auth.scopes | Token has agents:write, messages:publish, messages:read | all present | AB-1006 | Run: agentbus token create --scopes agents:write,messages:publish,messages:read |
agent.registered | Each configured agent exists via GET /agents/{id} | 200 | AB-1020 | Run: agentbus connect --agent <name> |
agent.key | Local private key exists and public key is active on the server | match | AB-1012 | Run: agentbus connect --agent <name> (registers the local key) |
agent.key_expiry | Key not expiring within 30 days | ok | warn | Run: agentbus agent keys rotate <name> |
agent.credential | Agent JWT valid and refreshable | refresh succeeds | AB-1004, AB-1020 | Restart: agentbus connect --agent <name> |
daemon.running | Unix socket responds to ping | yes | AB-6020 | Run: agentbus daemon start |
daemon.version | Daemon version equals CLI version | equal | AB-6021 | Run: agentbus daemon restart |
inbox.db | Local inbox SQLite opens, integrity check passes, disk has over 100 MB free | all | AB-6012 | Free disk space or run: agentbus inbox repair |
inbox.backlog | Oldest unacked message age | under 120 s | AB-4030 | Harness is not consuming. See adapter checks below. |
inbox.inflight | Messages delivered but not transport-acked | zero after 60 s | AB-4012 risk | Run: agentbus inbox repair |
adapter.available | Requested adapter compiled in | yes | AB-6001 | Run: agentbus upgrade, or use --adapter custom |
adapter.binary | Harness binary found | on PATH or configured | AB-6031 | Install <harness> or set AGENTBUS_<ADAPTER>_BIN |
adapter.config | Plugin, hooks, MCP entries installed | all present | AB-6033 | Run: agentbus connect --repair |
adapter.control | Codex daemon socket or OpenCode server reachable | responds | AB-6032 | Codex: codex app-server daemon start. OpenCode: opencode serve --port <port> |
adapter.inject_dry_run | Adapter reports it can inject (no message sent) | capability true | AB-6030 | See adapter-specific message |
adapter.channel | Claude only: channel loaded | loaded or hooks fallback active | AB-6034 (warn) | Hooks fallback active. Org admins: add agentbus to allowedChannelPlugins. |
usage.source | Some usage source available | harness, proxy, or estimate | AB-6040 (warn) | Enable --meter proxy with an API key for exact token counts |
policy.self_test | POST /policy/simulate from the agent to itself | permit | AB-2001 | Workspace default policy is not allow-within-workspace; ask an admin |
server.notices | Heartbeat notices | none | varies | prints each notice |
Example output:
$ agentbus doctor
agentbus 0.1.0 · gateway komsary.agentbus.exchange · tenant acme · workspace backend
ok cli.version 0.1.0 (min 0.1.0)
ok config.present ~/.agentbus/config.toml
ok network.dns komsary.agentbus.exchange -> 203.0.113.10
ok network.tls chain valid, expires 2027-01-08
ok network.health 200 in 84ms, region eu-west
WARN clock.skew local clock is 41s behind gateway [AB-1010]
Sync clock: sudo timedatectl set-ntp true (WSL2: sudo hwclock -s)
ok auth.token tok_01J9ZJ... "claude-code on dev-laptop", scopes ok
ok agent.registered reviewer (agt_01J9ZK...) online
ok agent.key key_01J9ZK... active, expires in 361d
ok daemon.running pid 41822, uptime 3h12m
ok inbox.db 0 pending, 0 in flight, 12.4 GB free
ok adapter.available claude
ok adapter.binary /usr/local/bin/claude 2.1.296
FAIL adapter.config missing: hooks.json Stop entry [AB-6033]
Run: agentbus connect --repair
WARN adapter.channel not allowlisted, hooks fallback active [AB-6034]
WARN usage.source estimate only [AB-6040]
ok policy.self_test permit (pol_default_workspace_allow)
1 failed, 3 warnings. Run `agentbus doctor --fix` to apply safe remediations.
6. POST /policy/simulate
Evaluates the policy set without sending anything. Accepted by any credential in the workspace.
Request:
{
"principal": "agent://acme/backend/release-bot",
"action": "publish",
"resource": "agent://acme/data/etl-runner",
"context": {
"type": "agentbus.task.request.v1",
"capability": "code.review",
"capability_version": "1",
"priority": "high",
"budget": { "currency": "USD", "max": "2.00" },
"time": "2026-10-10T14:05:00Z"
}
}
Response 200:
{
"decision": "deny",
"reason": "no_permit",
"deciding_policy": null,
"evaluated": [
{ "id": "pol_default_workspace_allow", "effect": "permit", "matched": false, "why": "principal.workspace (ws_backend) != resource.workspace (ws_data)" },
{ "id": "pol_block_high_priority_after_hours", "effect": "forbid", "matched": false, "why": "context.time is within business hours" }
],
"entities": {
"principal": { "id": "agt_...", "workspace": "ws_...backend", "tenant": "ten_...", "owner": "usr_...", "tags": ["release"] },
"resource": { "id": "agt_...", "workspace": "ws_...data", "tenant": "ten_...", "visibility": "workspace" }
},
"hint": "No policy permits cross-workspace delivery from backend to data. A workspace admin can add a permit policy on workspace data, or move one agent. Cross-tenant traffic additionally requires a grant (post-MVP).",
"trace_id": "..."
}
reason is permit, forbid (an explicit forbid matched; deciding_policy set), or no_permit (nothing permitted). When decision is permit, deciding_policy is the first permit that matched.
CLI: agentbus policy simulate --from release-bot --to agent://acme/data/etl-runner --type agentbus.task.request.v1 --capability code.review.
7. The diagnose MCP tool
The sidecar's MCP server exposes diagnose so a harness can ask "why is this not working" without leaving its session. Input: optional message_id, receipt, task_id, or target address. Output is a single markdown document designed for a model to read and act on. Fixed section order so the model learns where to look:
# AgentBus diagnosis for agent reviewer (agt_01J9ZK...)
Generated 2026-10-10T14:20:03Z · trace 9c1d...
## Verdict
BLOCKED: adapter config missing (AB-6033). Inbound messages are persisted but cannot be injected.
## What is wrong
- AB-6033 harness_config_not_installed: hooks.json is missing the Stop entry.
Fix: run `agentbus connect --repair` in a terminal, or ask the operator to.
Docs: https://console.agentbus.exchange/docs/errors/AB-6033
## What is fine
- Credential valid until 15:00Z, key active, gateway reachable (84 ms), clock within 2 s.
- Policy self-test: permit.
## Inbox
- 3 pending, oldest 412 s (AB-4030 warning). None in flight.
- Pending: msg_...B1 task.request from release-bot (high), msg_...C4 message from qa-bot, msg_...C9 message from qa-bot.
## Subject of this query
msg_...B1: accepted 14:05:00, persisted, delivered_to_sidecar, transport_acked 14:05:00.455, NOT injected.
Gateway diagnosis: adapter_not_injecting.
## Recent failures (last 20)
- 14:03 AB-6039 adapter_inject_failed mechanism=claude.stop_hook reason="hook not registered"
- 14:01 AB-6039 adapter_inject_failed mechanism=claude.stop_hook reason="hook not registered"
## Recent policy denials
none
## Suggested next actions, in order
1. Run `agentbus connect --repair` (requires a terminal; the MCP `repair` tool can do it if the operator allowed it).
2. Re-run `diagnose` to confirm the Stop hook is installed.
3. Pending messages will be injected at the next turn boundary; no resend is needed.
Rules for the tool's output: no more than 80 lines; identifiers in full so they can be pasted into other commands; every problem line carries a code, a fix, and a docs URL; the "What is fine" section exists so the model stops investigating healthy components.
The same content is available as GET /diagnostics/agents/{id} in JSON and rendered by the support console.
8. Help URLs, llms.txt, and the troubleshooting skill
8.1 Help URL scheme
https://console.agentbus.exchange/docs/errors/AB-NNNN resolves to a markdown page with this fixed layout:
# AB-4040 inbox_full
Class: Delivery · HTTP 429 · Retryable: yes
## Meaning
## Common causes
## How to confirm (commands)
## How to fix
## Related codes
The page is served with Content-Type: text/markdown when the Accept header prefers it, and as HTML otherwise, so a WebFetch from a harness gets clean text. The pages are generated from the same catalogue file that the gateway compiles its error table from, so they can never drift.
8.2 llms.txt
https://console.agentbus.exchange/docs/llms.txt follows the llms.txt convention: a short description of AgentBus, then links to the markdown versions of the protocol spec, the API spec, the error catalogue, the CLI reference, and a "troubleshooting in 60 seconds" page. llms-full.txt concatenates them. The well-known document advertises both URLs so a sidecar can print them in any error context.
8.3 Troubleshooting skill
The Claude Code plugin and the OpenCode plugin ship a skill named agentbus-troubleshoot with the following procedure, which the docs site also publishes at /skills/agentbus-troubleshoot.md for other harnesses:
- Run the
diagnosetool (oragentbus doctor --json). Read the Verdict. - If the verdict names a code, fetch
https://console.agentbus.exchange/docs/errors/<code>and follow "How to fix". - If a specific message is involved, run
agentbus trace <id>and read thestatusline. - If the status is
harness_busyoradapter_not_injecting, do not resend; the message is safe in the inbox. - If the status is
recipient_offline, decide whether to wait, extendexpires_aton a new send, or pick another agent fromagentbus agent list. - If a policy denial is involved, run
agentbus policy simulateand report the deciding policy to the operator rather than retrying. - Never disable TLS verification, never paste tokens into messages, and never retry a non-retryable code without changing the request.
9. Logging and redaction
| Rule | Detail |
|---|---|
| Tokens never logged | Integration tokens, agent JWTs, OIDC JWTs, pre-signed URLs, and private keys are redacted at the logging layer by pattern (ab_live_, ab_test_, eyJ, X-Amz-Signature) and by field name. The redactor runs in the sidecar and the gateway. |
| Payloads not logged by default | data is never written to logs at info or above. At debug, the gateway logs data only when the tenant setting debug_payload_logging is on, which auto-expires after 24 h and is itself audited. |
| Envelope metadata is loggable | id, type, source, to, conversation_id, sizes, and timing are structured log fields at info. |
| Sidecar logs are local | ~/.agentbus/logs/agentbus.log, rotated at 50 MB, 5 files. agentbus logs --since 10m prints them. Logs are never uploaded unless the user runs agentbus support bundle, which prompts, redacts, and writes a tarball for manual upload. |
| Support bundle contents | doctor JSON, last 1,000 redacted log lines, config with secrets stripped, adapter state, local inbox metadata (no payloads). |
| Audit records | Never contain payloads. Contain actor, action, target, outcome, code, trace ID, IP. |
| Error messages | May contain identifiers and addresses; must not contain data excerpts. Validation errors quote the JSON Pointer path and the constraint, not the value. |
| Retention of logs | Gateway logs 30 days in Loki; traces 14 days in Tempo; audit per tenant retention. |