Troubleshooting
Symptom-first recovery for connection, scope, project-reach, protocol, grant/lease, and question errors — with what is safe to retry versus when a human must act.
On this page
Start from the symptom and preserve durable state. Server control blocks name the stable error code, current state, permitted next operations, retryability, and any human action. If no authoritative response arrived, treat the outcome as unknown and read status before replaying a mutation.
Tools are missing or empty after setup
Classify startup before changing credentials:
- Not configured: add
https://mcp.semel.ai/mcpwith the exact Quickstart command. - Starting or provider transient: retry once with bounded backoff; do not erase credentials on timeout, 429, network failure, or 5xx.
- Terminal OAuth: for
invalid_grant, a rejected/used refresh token, missing provider refresh token, or logged-out state, stop concurrent clients sharing it and perform one harness-native login. - Server has tools, model session does not: reload the session; reauthorization will not fix stale model context.
- Some tools exist, one is absent: request only its missing scope/capability.
- Require live
initialize, SemelserverInfo, non-emptytools/list, and the needed tools in the current model session.
Authentication & scope errors
AUTHENTICATION_REQUIRED— complete one harness-native OAuth login, or have an owner rotate the named token through a secret reference.AUTHORIZATION_SCOPE_MISSING— request only the scope named by the live tool/control block, then reload the session. An unchanged retry cannot work.PROJECT_ACCESS_DENIED/CONTEXT_FORBIDDEN— use a reachable project/source or ask an owner to change the allowlist. Never probe for hidden project data.PROTOCOL_VERSION_UNSUPPORTED— run the inspected installer and start a new session. Never mutate under incompatible or security-revoked skill bytes.
Validation, versions, and idempotency
PAYLOAD_REJECTED/VALIDATION_FAILED— repair the field, size, content, evidence, or prerequisite named in the safe response; do not repeatedly send the same invalid payload.CONFLICTING_IDEMPOTENCY_REPLAY— the key belongs to different arguments. Read status/receipts, then use the original exact arguments or a fresh key for a genuinely new mutation.BRIEF_VERSION_CONFLICT— reread the full current brief, preserve all intended replacement sections, and ask the human to resolve the substantive conflict.- No response /
CONTROL_PLANE_UNREACHABLE— the client observed no authoritative result. Reconnect and read status before replaying with the same idempotency key.
Error codes
The full server error taxonomy. “Safe to retry” means an unchanged retry can succeed; “needs operator action” means a human must do something (approve, re-grant, re-mint) before it will.
AUTHENTICATION_REQUIREDdo not blind-retryThe request carried no valid bearer credential.
AUTHORIZATION_SCOPE_MISSINGdo not blind-retryneeds operator actionThe authenticated principal is missing a required scope.
PROJECT_ACCESS_DENIEDdo not blind-retryneeds operator actionThe authenticated principal has no grant to reach this project.
PROTOCOL_VERSION_UNSUPPORTEDdo not blind-retryNo compatible protocol major overlaps the caller-supported range.
GRANT_REQUIREDdo not blind-retryneeds operator actionNo operator-issued execution grant exists for this session yet.
GRANT_EXPIREDdo not blind-retryneeds operator actionThe execution grant is revoked, expired, or already consumed.
LEASE_EXPIREDdo not blind-retryThe current epoch lease expired; a recovery or new claim is required.
STALE_FENCEdo not blind-retryThis write came from a fence generation that is no longer current.
SEQUENCE_GAPdo not blind-retryThe submitted sequence number is not the expected next value.
CONFLICTING_IDEMPOTENCY_REPLAYdo not blind-retryThe idempotency key was already used with different arguments.
QUESTION_OPENsafe to retryA durable question is open and awaiting an accepted answer.
QUESTION_DELIVERY_DEGRADEDsafe to retryA notification channel is degraded; the canonical inbox record is unaffected.
QUESTION_RESPONSE_DEADLINE_EXCEEDEDsafe to retryneeds operator actionThe response deadline passed with no accepted answer; the question stays open.
BRIEF_VERSION_CONFLICTdo not blind-retryneeds operator actionThe pinned brief base moved before finalization.
RUN_ALREADY_TERMINALdo not blind-retryThe run is already terminal; read review_status — there is nothing to cancel.
CANCELLEDdo not blind-retryThis session was cancelled; no further mutation can complete it.
PAYLOAD_REJECTEDdo not blind-retryThe payload violated a bound, forbidden field, or content rule.
VALIDATION_FAILEDdo not blind-retryThe submitted result failed a repairable schema/evidence/prerequisite rule.
CONTEXT_FORBIDDENdo not blind-retryneeds operator actionThe caller's scope or project grant does not reach this context source.
CONTEXT_UNAVAILABLEsafe to retryThe requested context source or citation could not be resolved.
Invalid calls and exact recovery
These deterministic fixtures preserve the actual boundary distinction: authenticated domain failures are MCP result.isError responses with matching text and structured bodies, while a rejected credential stops at the HTTP 401 challenge before any tool runs. Example IDs and timestamps are inert fixtures.
Missing scope
Call local review origination without review:execute.
{
"toolName": "review_start",
"arguments": {
"briefId": "brf_fixture_checkout",
"execution": "local",
"idempotencyKey": "review-start-local-v1"
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "{\"error\":{\"kind\":\"forbidden\",\"message\":\"this action requires the review:execute scope\",\"details\":{\"reason\":\"AUTHORIZATION_SCOPE_MISSING\",\"missingScope\":\"review:execute\",\"repair\":\"request_additional_scope\"},\"retryable\":false,\"requestId\":\"req_fixture_scope\"}}"
}
],
"structuredContent": {
"error": {
"kind": "forbidden",
"message": "this action requires the review:execute scope",
"details": {
"reason": "AUTHORIZATION_SCOPE_MISSING",
"missingScope": "review:execute",
"repair": "request_additional_scope"
},
"retryable": false,
"requestId": "req_fixture_scope"
}
},
"isError": true
}
}Correction: A human grants only review:execute through delegated consent or agent-token configuration; reload the session and repeat the same logical mutation.
Malformed input or cross-field refinement
Omit both identifiers required by review_execution_status.
{
"toolName": "review_execution_status",
"arguments": {}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "{\"error\":{\"kind\":\"validation\",\"message\":\"invalid arguments for review_execution_status: reviewSessionId or executionId is required\",\"details\":{\"issues\":[{\"code\":\"custom\",\"message\":\"reviewSessionId or executionId is required\",\"path\":[]}]},\"retryable\":false,\"requestId\":\"req_fixture_validation\"}}"
}
],
"structuredContent": {
"error": {
"kind": "validation",
"message": "invalid arguments for review_execution_status: reviewSessionId or executionId is required",
"details": {
"issues": [
{
"code": "custom",
"message": "reviewSessionId or executionId is required",
"path": []
}
]
},
"retryable": false,
"requestId": "req_fixture_validation"
}
},
"isError": true
}
}Correction: Supply one authoritative identifier returned by the claim or session status.
{
"executionId": "xex_fixture_engineering"
}Conflicting idempotency replay
Reuse a checkpoint idempotency key with changed receipt arguments.
{
"toolName": "review_execution_checkpoint_append",
"arguments": {
"executionId": "xex_fixture_engineering",
"fenceGeneration": 3,
"seq": 3,
"milestoneName": "validation_result",
"safeSummary": "Changed payload.",
"idempotencyKey": "checkpoint-3-original"
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "{\"error\":{\"kind\":\"conflict\",\"message\":\"The idempotency key was already used with different arguments.\",\"details\":{\"state\":{\"sessionState\":\"running\",\"executionId\":\"xex_fixture_engineering\",\"epoch\":3,\"protocolVersion\":\"1.1\",\"bundleVersion\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"},\"allowedNextOperations\":[{\"operation\":\"review_execution_sync\",\"preconditions\":[\"Follow the current server control block.\"]}],\"completion\":{\"complete\":false,\"unmetRequirements\":[\"The execution has not reached a terminal accepted submit.\"],\"certificateState\":\"not_applicable\"},\"progress\":{\"checkpointHighWaterMark\":2,\"openQuestionCount\":0,\"leaseExpiresAt\":\"2026-09-07T18:15:00.000Z\",\"suggestedPollAt\":\"2026-09-07T18:05:00.000Z\"},\"operatorAction\":{\"required\":false},\"error\":{\"code\":\"CONFLICTING_IDEMPOTENCY_REPLAY\",\"retryable\":false,\"currentState\":\"running\",\"permittedNextOperations\":[\"review_execution_sync\"],\"safeText\":\"The idempotency key was already used with different arguments.\"}},\"retryable\":false,\"requestId\":\"req_fixture_idempotency\"}}"
}
],
"structuredContent": {
"error": {
"kind": "conflict",
"message": "The idempotency key was already used with different arguments.",
"details": {
"state": {
"sessionState": "running",
"executionId": "xex_fixture_engineering",
"epoch": 3,
"protocolVersion": "1.1",
"bundleVersion": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"allowedNextOperations": [
{
"operation": "review_execution_sync",
"preconditions": [
"Follow the current server control block."
]
}
],
"completion": {
"complete": false,
"unmetRequirements": [
"The execution has not reached a terminal accepted submit."
],
"certificateState": "not_applicable"
},
"progress": {
"checkpointHighWaterMark": 2,
"openQuestionCount": 0,
"leaseExpiresAt": "2026-09-07T18:15:00.000Z",
"suggestedPollAt": "2026-09-07T18:05:00.000Z"
},
"operatorAction": {
"required": false
},
"error": {
"code": "CONFLICTING_IDEMPOTENCY_REPLAY",
"retryable": false,
"currentState": "running",
"permittedNextOperations": [
"review_execution_sync"
],
"safeText": "The idempotency key was already used with different arguments."
}
},
"retryable": false,
"requestId": "req_fixture_idempotency"
}
},
"isError": true
}
}Correction: Read status and receipts. Replay the original unchanged arguments with the original key, or use a fresh key only for a new logical checkpoint.
{
"executionId": "xex_fixture_engineering"
}Brief version conflict
Replace a brief using a stale ifVersionNum.
{
"toolName": "brief_update",
"arguments": {
"briefId": "brf_fixture_checkout",
"content": {},
"ifVersionNum": 4,
"idempotencyKey": "brief-update-v4"
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "{\"error\":{\"kind\":\"conflict\",\"message\":\"brief moved to a newer version since you loaded it — reload and retry\",\"details\":{\"reason\":\"BRIEF_VERSION_CONFLICT\",\"ifVersionNum\":4,\"currentVersionNum\":5},\"retryable\":false,\"requestId\":\"req_fixture_brief_version\"}}"
}
],
"structuredContent": {
"error": {
"kind": "conflict",
"message": "brief moved to a newer version since you loaded it — reload and retry",
"details": {
"reason": "BRIEF_VERSION_CONFLICT",
"ifVersionNum": 4,
"currentVersionNum": 5
},
"retryable": false,
"requestId": "req_fixture_brief_version"
}
},
"isError": true
}
}Correction: Reread the full brief, preserve every untouched key, reconcile the human-visible conflict, and use a new mutation key for the changed replacement.
{
"briefId": "brf_fixture_checkout"
}Stale execution fence
Heartbeat with a fence generation superseded by a handoff or recovery claim.
{
"toolName": "review_execution_heartbeat",
"arguments": {
"executionId": "xex_fixture_engineering",
"fenceGeneration": 2,
"idempotencyKey": "heartbeat-stale-fence"
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "{\"error\":{\"kind\":\"conflict\",\"message\":\"This write came from fence generation 2; the current generation is 3.\",\"details\":{\"state\":{\"sessionState\":\"running\",\"executionId\":\"xex_fixture_engineering\",\"epoch\":3,\"protocolVersion\":\"1.1\",\"bundleVersion\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"},\"allowedNextOperations\":[{\"operation\":\"review_execution_status\",\"preconditions\":[\"Follow the current server control block.\"]}],\"completion\":{\"complete\":false,\"unmetRequirements\":[\"The execution has not reached a terminal accepted submit.\"],\"certificateState\":\"not_applicable\"},\"progress\":{\"checkpointHighWaterMark\":2,\"openQuestionCount\":0,\"leaseExpiresAt\":\"2026-09-07T18:15:00.000Z\",\"suggestedPollAt\":\"2026-09-07T18:05:00.000Z\"},\"operatorAction\":{\"required\":false},\"error\":{\"code\":\"STALE_FENCE\",\"retryable\":false,\"currentState\":\"running\",\"permittedNextOperations\":[\"review_execution_status\"],\"safeText\":\"This write came from fence generation 2; the current generation is 3.\"}},\"retryable\":false,\"requestId\":\"req_fixture_stale_fence\"}}"
}
],
"structuredContent": {
"error": {
"kind": "conflict",
"message": "This write came from fence generation 2; the current generation is 3.",
"details": {
"state": {
"sessionState": "running",
"executionId": "xex_fixture_engineering",
"epoch": 3,
"protocolVersion": "1.1",
"bundleVersion": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"allowedNextOperations": [
{
"operation": "review_execution_status",
"preconditions": [
"Follow the current server control block."
]
}
],
"completion": {
"complete": false,
"unmetRequirements": [
"The execution has not reached a terminal accepted submit."
],
"certificateState": "not_applicable"
},
"progress": {
"checkpointHighWaterMark": 2,
"openQuestionCount": 0,
"leaseExpiresAt": "2026-09-07T18:15:00.000Z",
"suggestedPollAt": "2026-09-07T18:05:00.000Z"
},
"operatorAction": {
"required": false
},
"error": {
"code": "STALE_FENCE",
"retryable": false,
"currentState": "running",
"permittedNextOperations": [
"review_execution_status"
],
"safeText": "This write came from fence generation 2; the current generation is 3."
}
},
"retryable": false,
"requestId": "req_fixture_stale_fence"
}
},
"isError": true
}
}Correction: Discard the local fence and inspect the authoritative execution before any mutation.
{
"executionId": "xex_fixture_engineering"
}Expired execution lease
Heartbeat after the current epoch lease has expired.
{
"toolName": "review_execution_heartbeat",
"arguments": {
"executionId": "xex_fixture_engineering",
"fenceGeneration": 3,
"idempotencyKey": "heartbeat-expired-lease"
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "{\"error\":{\"kind\":\"conflict\",\"message\":\"The current epoch lease already expired; reclaim via review_execution_claim.\",\"details\":{\"state\":{\"sessionState\":\"running\",\"executionId\":\"xex_fixture_engineering\",\"epoch\":3,\"protocolVersion\":\"1.1\",\"bundleVersion\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"},\"allowedNextOperations\":[{\"operation\":\"review_execution_claim\",\"preconditions\":[\"Follow the current server control block.\"]}],\"completion\":{\"complete\":false,\"unmetRequirements\":[\"The execution has not reached a terminal accepted submit.\"],\"certificateState\":\"not_applicable\"},\"progress\":{\"checkpointHighWaterMark\":2,\"openQuestionCount\":0,\"leaseExpiresAt\":\"2026-09-07T17:55:00.000Z\",\"suggestedPollAt\":\"2026-09-07T18:05:00.000Z\"},\"operatorAction\":{\"required\":false},\"error\":{\"code\":\"LEASE_EXPIRED\",\"retryable\":false,\"currentState\":\"running\",\"permittedNextOperations\":[\"review_execution_claim\"],\"safeText\":\"The current epoch lease already expired; reclaim via review_execution_claim.\"}},\"retryable\":false,\"requestId\":\"req_fixture_expired_lease\"}}"
}
],
"structuredContent": {
"error": {
"kind": "conflict",
"message": "The current epoch lease already expired; reclaim via review_execution_claim.",
"details": {
"state": {
"sessionState": "running",
"executionId": "xex_fixture_engineering",
"epoch": 3,
"protocolVersion": "1.1",
"bundleVersion": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"allowedNextOperations": [
{
"operation": "review_execution_claim",
"preconditions": [
"Follow the current server control block."
]
}
],
"completion": {
"complete": false,
"unmetRequirements": [
"The execution has not reached a terminal accepted submit."
],
"certificateState": "not_applicable"
},
"progress": {
"checkpointHighWaterMark": 2,
"openQuestionCount": 0,
"leaseExpiresAt": "2026-09-07T17:55:00.000Z",
"suggestedPollAt": "2026-09-07T18:05:00.000Z"
},
"operatorAction": {
"required": false
},
"error": {
"code": "LEASE_EXPIRED",
"retryable": false,
"currentState": "running",
"permittedNextOperations": [
"review_execution_claim"
],
"safeText": "The current epoch lease already expired; reclaim via review_execution_claim."
}
},
"retryable": false,
"requestId": "req_fixture_expired_lease"
}
},
"isError": true
}
}Correction: Read status, then follow only the returned recovery or fresh human-grant claim path.
{
"executionId": "xex_fixture_engineering"
}Review configuration missing
Start the first review for a project with no configured AI reviewer.
{
"toolName": "review_start",
"arguments": {
"briefId": "brf_fixture_checkout",
"idempotencyKey": "review-start-configless"
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "{\"error\":{\"kind\":\"validation\",\"message\":\"configure at least one AI reviewer in the portal before starting the first review pass\",\"retryable\":false,\"requestId\":\"req_fixture_configless\"}}"
}
],
"structuredContent": {
"error": {
"kind": "validation",
"message": "configure at least one AI reviewer in the portal before starting the first review pass",
"retryable": false,
"requestId": "req_fixture_configless"
}
},
"isError": true
}
}Correction: A human configures at least one project reviewer/provider/model in the Semel portal; then the agent retries review_start with a new logical-attempt key.
Pinned artifact publication missing
Fetch a pinned active skill whose exact role/version/hash row or bytes are unavailable.
{
"toolName": "review_execution_skill_get",
"arguments": {
"executionId": "xex_fixture_engineering",
"role": "engineering"
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "{\"error\":{\"kind\":\"not_found\",\"message\":\"the pinned engineering skill artifact is unavailable for this execution\",\"details\":{\"state\":{\"sessionState\":\"running\",\"executionId\":\"xex_fixture_engineering\",\"epoch\":3,\"protocolVersion\":\"1.1\",\"bundleVersion\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"},\"allowedNextOperations\":[{\"operation\":\"review_execution_status\",\"preconditions\":[\"Follow the current server control block.\"]}],\"completion\":{\"complete\":false,\"unmetRequirements\":[\"The execution has not reached a terminal accepted submit.\"],\"certificateState\":\"not_applicable\"},\"progress\":{\"checkpointHighWaterMark\":2,\"openQuestionCount\":0,\"leaseExpiresAt\":\"2026-09-07T18:15:00.000Z\",\"suggestedPollAt\":\"2026-09-07T18:05:00.000Z\"},\"operatorAction\":{\"required\":false},\"error\":{\"code\":\"PAYLOAD_REJECTED\",\"retryable\":false,\"currentState\":\"running\",\"permittedNextOperations\":[\"review_execution_status\"],\"safeText\":\"the pinned engineering skill artifact is unavailable for this execution\"}},\"retryable\":false,\"requestId\":\"req_fixture_publication\"}}"
}
],
"structuredContent": {
"error": {
"kind": "not_found",
"message": "the pinned engineering skill artifact is unavailable for this execution",
"details": {
"state": {
"sessionState": "running",
"executionId": "xex_fixture_engineering",
"epoch": 3,
"protocolVersion": "1.1",
"bundleVersion": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"allowedNextOperations": [
{
"operation": "review_execution_status",
"preconditions": [
"Follow the current server control block."
]
}
],
"completion": {
"complete": false,
"unmetRequirements": [
"The execution has not reached a terminal accepted submit."
],
"certificateState": "not_applicable"
},
"progress": {
"checkpointHighWaterMark": 2,
"openQuestionCount": 0,
"leaseExpiresAt": "2026-09-07T18:15:00.000Z",
"suggestedPollAt": "2026-09-07T18:05:00.000Z"
},
"operatorAction": {
"required": false
},
"error": {
"code": "PAYLOAD_REJECTED",
"retryable": false,
"currentState": "running",
"permittedNextOperations": [
"review_execution_status"
],
"safeText": "the pinned engineering skill artifact is unavailable for this execution"
}
},
"retryable": false,
"requestId": "req_fixture_publication"
}
},
"isError": true
}
}Correction: Stop execution and ask an operator to publish the exact pinned role/version/hash. Check status after publication; never substitute latest bytes.
{
"executionId": "xex_fixture_engineering"
}Revoked or rejected login
Initialize MCP with a bearer credential the server evaluated and rejected.
{
"method": "POST",
"url": "https://mcp.semel.ai/mcp",
"bearer": "<redacted rejected credential>"
}{
"status": 401,
"headers": {
"cache-control": "no-store",
"www-authenticate": "Bearer resource_metadata=\"https://mcp.semel.ai/.well-known/oauth-protected-resource/mcp\", error=\"invalid_token\""
}
}Correction: Stop concurrent clients sharing the credential, complete one harness-native login, reload the session, and require live initialize plus tools/list before continuing.
Grants, leases, and lost sessions
Call review_execution_status, then review_execution_sync, before recovery. GRANT_REQUIRED / GRANT_EXPIRED: create a grant request if permitted and wait for a human to approve a fresh grant. LEASE_EXPIRED / STALE_FENCE: stop mutating with the old claim and follow the returned legal claim path. SEQUENCE_GAP: synchronize and send exactly the next sequence; never skip or renumber history. RUN_ALREADY_TERMINAL / CANCELLED: read final status and stop. Do not create duplicate reviews, sessions, or epochs.
Questions and notification delivery
QUESTION_OPEN means execution is waiting for an accepted human answer; poll/read status without inventing one. QUESTION_DELIVERY_DEGRADED means Slack/email delivery is impaired while the canonical Semel inbox record remains valid; direct the human to Semel. QUESTION_RESPONSE_DEADLINE_EXCEEDED leaves the question open and may supply an operator URI; a person decides the response or recovery.
Context and export failures
CONTEXT_UNAVAILABLE is retryable only as the returned control block permits; relist sources and search again rather than guessing a citation. If brief_export_package fails, no implementation-ready package exists. Repair the reported brief/export condition and retry with the correct idempotency behavior; do not fall back to deprecated brief_export_markdown as a verified handoff.
Installer and update recovery
Unknown release key, invalid Ed25519 signature, identity/hash mismatch, incompatible protocol, malformed skill metadata, or a non-HTTPS artifact URL must stop installation. Keep the prior copy. failed_restored means the old verified copy was restored; inspect the reason before retrying. failed_restore reports backup paths and needs manual operator restoration. A custom local file is refused unless the operator has preserved changes and deliberately chooses --allow-custom.