{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "name": "SOAT API error codes",
  "version": "0.91.0",
  "description": "Every error code the SOAT REST API, MCP surface and SDK can return, with its HTTP status and what it means. Generated from the server source (packages/server/src/errors/codes.ts).",
  "shape": {
    "description": "Every 4xx and 5xx response body. `error.code` is a stable identifier safe to branch on; `error.message` is human-readable and may change; `error.hint` says what to do about the failure and `error.docs_url` addresses the reference section for the code; `error.meta` carries per-code context when available.",
    "example": {
      "error": {
        "code": "RESOURCE_NOT_FOUND",
        "message": "Project 'proj_abc123' not found.",
        "hint": "Check the id, and check that the credential can see the project that owns the resource — a resource in another project is indistinguishable from one that does not exist. List the collection to confirm.",
        "docs_url": "https://soat.ttoss.dev/docs/error-codes#resource_not_found"
      }
    }
  },
  "codes": [
    {
      "code": "ACTIVITY_INVALID_CURSOR",
      "http_status": 400,
      "description": "The activity feed cursor is malformed or does not decode to a valid (created_at, id) position.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#activity_invalid_cursor"
    },
    {
      "code": "ACTOR_HAS_MESSAGES",
      "http_status": 409,
      "description": "The actor has linked session messages and cannot be deleted.",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#actor_has_messages"
    },
    {
      "code": "ACTOR_NOT_FOUND",
      "http_status": 400,
      "description": "A referenced actor does not exist.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#actor_not_found"
    },
    {
      "code": "AGENT_AND_CHAT_EXCLUSIVE",
      "http_status": 400,
      "description": "An actor cannot have both an agent_id and a chat_id assigned simultaneously. Set one or the other, not both.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#agent_and_chat_exclusive"
    },
    {
      "code": "AGENT_HAS_DEPENDENTS",
      "http_status": 409,
      "description": "The agent is referenced by one or more generations, traces, deciders, accepted shares or ingestion rules and cannot be deleted. `meta.decider_count` names the deciders, which block deletion even under `force=true` and must be deleted or repointed first; generations, traces, accepted shares (`meta.accepted_share_count`) and its own project's ingestion rules (`meta.ingestion_rule_count`) block only until `force=true`, which revokes the shares and leaves the rules naming a converter that is gone.",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#agent_has_dependents"
    },
    {
      "code": "AGENT_NOT_FOUND",
      "http_status": 400,
      "description": "A referenced agent does not exist.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#agent_not_found"
    },
    {
      "code": "AI_PROVIDER_ERROR",
      "http_status": 502,
      "description": "The upstream AI provider returned an error (e.g. insufficient credits, rate limit, or the provider is unreachable).",
      "resolution": "The upstream model provider failed, not this server. Check the provider credential and the account behind it (credits, rate limits, model access), then retry with backoff.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#ai_provider_error"
    },
    {
      "code": "AI_PROVIDER_HAS_DEPENDENTS",
      "http_status": 409,
      "description": "The AI provider still has dependents. Live references (chats, agents, model-route targets) always block deletion and must be deleted or repointed first. Soft dependents (price overrides, usage records) block only until force=true, which drops the overrides and unlinks usage history. The error meta reports the counts, a sample of offending IDs, and a `forcible` flag.",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#ai_provider_has_dependents"
    },
    {
      "code": "AI_PROVIDER_MISCONFIGURED",
      "http_status": 400,
      "description": "The AI provider record is missing configuration the provider type requires — for example a `vertex` provider with no Google Cloud project in `config.project` and no service-account key file linked as its secret, a `bedrock`/`vertex` record that links no credential at all on a deployment that does not let a record use the deployment's own, or one whose linked secret holds no usable credential.",
      "resolution": "The provider record is missing something it needs to make a call — usually the API key secret or the base URL. A `bedrock` or `vertex` record linking no credential is this too: it would sign with the deployment's own, which only an operator may allow. Update the AI provider and retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#ai_provider_misconfigured"
    },
    {
      "code": "AI_PROVIDER_NOT_FOUND",
      "http_status": 400,
      "description": "A referenced AI provider does not exist.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#ai_provider_not_found"
    },
    {
      "code": "API_KEY_PROJECT_SCOPE",
      "http_status": 403,
      "description": "The credential (API key or OAuth token) is bound to one project and the request targets a different one. This project binding is a hard boundary that the owner’s admin role does not lift — admin only relaxes the project create/delete gate, never the per-credential project scope for resource operations. Mint a key scoped to the target project (or an unscoped key) to operate there. The error meta reports `scoped_project` and `requested_project`.",
      "resolution": "This API key is scoped to a single project and the request targets another one (or none). Omit `project_id` to use the key's own project, or use an unscoped credential.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#api_key_project_scope"
    },
    {
      "code": "APPROVAL_ALREADY_RESOLVED",
      "http_status": 409,
      "description": "The approval item has already been resolved (approved, rejected, or expired) and cannot be resolved again.",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#approval_already_resolved"
    },
    {
      "code": "APPROVAL_EXPIRED",
      "http_status": 409,
      "description": "The approval item has expired and can never execute. Its supporting evidence is stale; a fresh proposal is required.",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#approval_expired"
    },
    {
      "code": "APPROVAL_INVALID_EDIT",
      "http_status": 400,
      "description": "The edited arguments supplied on edit-then-approve must be a JSON object, and must satisfy the tool's own `parameters` schema.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#approval_invalid_edit"
    },
    {
      "code": "APPROVAL_NOT_FOUND",
      "http_status": 404,
      "description": "The approval item does not exist or is not accessible.",
      "resolution": "Check the id and the project the credential can see, then retry. Listing the collection confirms whether the resource exists.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#approval_not_found"
    },
    {
      "code": "APPROVAL_REASON_REQUIRED",
      "http_status": 400,
      "description": "A reason is required when rejecting an approval item.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#approval_reason_required"
    },
    {
      "code": "BOOTSTRAP_ALREADY_COMPLETED",
      "http_status": 409,
      "description": "The instance already has at least one user, so the one-time bootstrap of the first admin cannot run again.",
      "resolution": "The first admin already exists, so bootstrap is closed for good. Sign in instead, and create further users with `POST /api/v1/users`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#bootstrap_already_completed"
    },
    {
      "code": "CHAIN_NOT_FOUND",
      "http_status": 404,
      "description": "The continuation chain does not exist or is not accessible.",
      "resolution": "Check the id and the project the credential can see, then retry. Listing the collection confirms whether the resource exists.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#chain_not_found"
    },
    {
      "code": "CHAT_NOT_FOUND",
      "http_status": 400,
      "description": "A referenced chat does not exist.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#chat_not_found"
    },
    {
      "code": "CONVERSATION_POSITION_CONFLICT",
      "http_status": 409,
      "description": "Another write took the message's `position` in the conversation at the same time. Nothing was written: retry the write.",
      "resolution": "Retry the write unchanged: nothing was stored, and the retry resolves its position again.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#conversation_position_conflict"
    },
    {
      "code": "CONVERSION_TIMEOUT",
      "http_status": 500,
      "description": "Recorded on a document, never returned by a request: its converter deferred with `{ status: \"pending\" }` and did not call back within `CONVERSION_STALL_TIMEOUT_MS` (thirty minutes by default), so the next read marked it failed.",
      "resolution": "Check that the converter calls back to the document's callback URL, then ingest the document again. Raise `CONVERSION_STALL_TIMEOUT_MS` for a converter that legitimately takes longer.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#conversion_timeout"
    },
    {
      "code": "CONVERTER_FAILED",
      "http_status": 422,
      "description": "The ingestion converter (tool or agent) failed to run, an agent converter returned an async deferral (unsupported — agent converters are always awaited inline), or a tool converter returned an async deferral during synchronous ingestion (`?wait=true`, which cannot wait for a callback).",
      "resolution": "The request was accepted and then could not be carried out. The failure is in the work, not the request shape — read `meta` and the trace for which step failed before retrying.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#converter_failed"
    },
    {
      "code": "CONVERTER_OUTPUT_INVALID",
      "http_status": 422,
      "description": "The ingestion converter returned an unrecognized output shape. Expected a string, `{ pages: [{ text, page_number }] }`, or `{ status: \"pending\" }`.",
      "resolution": "The request was accepted and then could not be carried out. The failure is in the work, not the request shape — read `meta` and the trace for which step failed before retrying.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#converter_output_invalid"
    },
    {
      "code": "DECIDER_AGENT_NOT_TOOL_LESS",
      "http_status": 400,
      "description": "The agent a decider evaluates with has a tool surface: a tool binding left active by `active_tool_ids`, or a `knowledge_config.write_memory_store_id`. A decision has no resume route, and a tool call during evaluation would take a side effect the decision cannot record, so a decider agent carries no tools. Knowledge retrieval stays available.",
      "resolution": "Point the decider at an agent with no `tool_bindings` and no `knowledge_config.write_memory_store_id`, or remove them from this one with `PATCH /api/v1/agents/{agent_id}`. The agent's `instructions` and knowledge retrieval remain the place for domain context.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#decider_agent_not_tool_less"
    },
    {
      "code": "DECIDER_TOOL_NOT_CALLABLE",
      "http_status": 400,
      "description": "The tool a decider evaluates with cannot answer a decision. Only `http` and `pipeline` tools can: a `client` tool has no caller to hand the call to, and an `mcp` or `builtin` tool needs an `action` a decider does not carry. A tool whose `preset_parameters` pin `input` or `questions` is refused too, since presets are merged over the call input and would replace the caller's input or the questions. `meta.tool_id` names the tool, with `meta.type` or `meta.pinned`.",
      "resolution": "Point the decider at an `http` or `pipeline` tool with no `input` or `questions` in its `preset_parameters`. Reach an `mcp` or `builtin` tool through a `pipeline` step, which names its own `action`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#decider_tool_not_callable"
    },
    {
      "code": "DECISION_ANSWER_INVALID",
      "http_status": 502,
      "description": "Recorded on a decision, never returned by a request: the tool answered outside the contract — not a JSON object with an `answers` array, an answer missing, repeated or naming no question, a value outside the question's answer space, a probability or confidence outside 0–1, or a field the contract does not define. The message names the answer and the field.",
      "resolution": "Make the tool answer `{ answers: [{ name, probability | choice | score, probabilities?, confidence? }] }`, one per question, as OpenAI's Decisions API does; map an engine's own fields with the tool's `output_mapping` or a `pipeline` tool's `output`. Then request a new decision.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#decision_answer_invalid"
    },
    {
      "code": "DECISION_INTERRUPTED",
      "http_status": 500,
      "description": "Recorded on a decision, never returned by a request: the process evaluating it stopped before it settled. The evaluated input is not stored, so the decision cannot be re-run; request a new one.",
      "resolution": "Request a new decision with `POST /api/v1/deciders/{decider_id}/decisions` or `POST /api/v1/decisions`; nothing about the interrupted one can be resumed.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#decision_interrupted"
    },
    {
      "code": "DOCUMENT_ALREADY_WITHDRAWN",
      "http_status": 409,
      "description": "The document is already withdrawn, so there is nothing to take out. Restore an earlier version to bring it back.",
      "resolution": "The document is already out of every default read. To bring it back, restore the version before the withdrawal.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#document_already_withdrawn"
    },
    {
      "code": "DOCUMENT_RELATION_EXISTS",
      "http_status": 409,
      "description": "That relation is already asserted between the two documents. Re-asserting the same edge is the same fact, so there is nothing to add.",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#document_relation_exists"
    },
    {
      "code": "EMBEDDING_NOT_CONFIGURED",
      "http_status": 503,
      "description": "The embedding service is not configured. Set EMBEDDING_PROVIDER and EMBEDDING_MODEL environment variables.",
      "resolution": "Knowledge search needs an embedding model. Configure one on the project or the AI provider before ingesting or searching.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#embedding_not_configured"
    },
    {
      "code": "EVAL_SCORING_FAILED",
      "http_status": 500,
      "description": "Recorded on an eval result, never returned by a request: a scorer could not grade the item's output for a reason no more specific code names. The item is excluded from the aggregates rather than scored 0.",
      "resolution": "Read the message for the scorer's failure, fix the scorer's configuration, and run the eval again.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#eval_scoring_failed"
    },
    {
      "code": "EXCEPTION_ALREADY_RESOLVED",
      "http_status": 409,
      "description": "The exception item has already been resolved and cannot be acknowledged or resolved again.",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#exception_already_resolved"
    },
    {
      "code": "EXCEPTION_NOT_FOUND",
      "http_status": 404,
      "description": "The exception item does not exist or is not accessible.",
      "resolution": "Check the id and the project the credential can see, then retry. Listing the collection confirms whether the resource exists.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#exception_not_found"
    },
    {
      "code": "EXPRESSION_FAILED",
      "http_status": 422,
      "description": "A JSON Logic expression failed to evaluate: it names an operator the engine does not know, or it ran a `throw`. The message carries what the expression threw.",
      "resolution": "Fix the JSON Logic expression the message names: an unknown operator, or a `throw` the expression reached with the data it was given.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#expression_failed"
    },
    {
      "code": "FILE_ALREADY_INGESTED",
      "http_status": 409,
      "description": "The file already backs a Document (a file can only be ingested once). Use POST /documents/{document_id}/ingest to re-process the existing document, or upload a new copy of the file to ingest it under a different path/strategy.",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#file_already_ingested"
    },
    {
      "code": "FILE_DOWNLOAD_URL_NOT_CONFIGURED",
      "http_status": 500,
      "description": "An ingestion rule with file_delivery: download_url requires SOAT_BASE_URL to be set — the URL is fetched by an external converter that cannot resolve a relative or localhost address.",
      "resolution": "Retry with backoff. If it persists, the server log carries the detail the response deliberately omits.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#file_download_url_not_configured"
    },
    {
      "code": "FILE_HAS_DEPENDENTS",
      "http_status": 409,
      "description": "The file is referenced by one or more records and cannot be deleted. Delete the dependent records first.",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#file_has_dependents"
    },
    {
      "code": "FILE_NOT_FOUND",
      "http_status": 400,
      "description": "The referenced file does not exist.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#file_not_found"
    },
    {
      "code": "FILE_PARSE_FAILED",
      "http_status": 400,
      "description": "The referenced file contains no extractable text.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#file_parse_failed"
    },
    {
      "code": "FILE_STORAGE_MISCONFIGURED",
      "http_status": 500,
      "description": "The file storage backend is not configured correctly — an unknown FILES_STORAGE_PROVIDER, an unsupported storage type, or a missing required variable (e.g. FILES_STORAGE_DIR for local, FILES_S3_BUCKET for s3).",
      "resolution": "Retry with backoff. If it persists, the server log carries the detail the response deliberately omits.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#file_storage_misconfigured"
    },
    {
      "code": "FILE_TOO_LARGE_FOR_SYNC",
      "http_status": 413,
      "description": "The file is too large to ingest synchronously. Retry without `?wait=true` to run ingestion in the background and poll the document status.",
      "resolution": "The file is too large to parse inside the request. Call the same operation without `wait=true` and poll the handle it returns.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#file_too_large_for_sync"
    },
    {
      "code": "FORBIDDEN",
      "http_status": 403,
      "description": "The authenticated user does not have permission to perform this action.",
      "resolution": "The credential authenticated but is not allowed this action. Attach an IAM policy granting the action to the caller, or use a credential that has it.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#forbidden"
    },
    {
      "code": "FORCED_TOOL_CHOICE_CANNOT_STOP",
      "http_status": 400,
      "description": "The agent forces tool use on every step (`tool_choice: \"required\"`, or the `{ type: \"tool\" }` object form) but declares no `has_tool_call` stop condition, so no turn it runs could ever end by answering — only by exhausting `max_steps`. Declare the terminal condition, or drop the forcing to `\"auto\"` and force a specific step with `step_rules` instead.",
      "resolution": "Add `{ \"type\": \"has_tool_call\", \"tool_name\": \"<your done tool>\" }` to `stop_conditions`, or set `tool_choice` to `\"auto\"` and force the step you actually care about with `step_rules`. `max_chain_generations` does not satisfy this — it bounds a chain, it never ends a turn.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#forced_tool_choice_cannot_stop"
    },
    {
      "code": "FORMATION_DELETE_FAILED",
      "http_status": 409,
      "description": "One or more of the formation's resources could not be deleted, so the stack is left in `delete_failed`. `meta.failures` names each blocking resource (its logical id, type, and the underlying error) — the common case is a resource the platform refuses to delete on its own, such as an agent that has generation or trace history. Resolve those, then delete the formation again.",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#formation_delete_failed"
    },
    {
      "code": "FORMATION_HANDLER_FAILED",
      "http_status": 502,
      "description": "A resource type registered by the deployment operator delegates its lifecycle to an external HTTP handler, and that handler did not answer successfully — it returned a non-2xx status, timed out, was unreachable, or replied with a body the protocol does not allow (a create with no `physical_resource_id`, for instance). `meta.resource_type` and `meta.request_type` name the type and the operation, and the handler's own message is relayed when it sent one. This is an operator-side failure: the template is not at fault and re-deploying it unchanged will fail the same way until the handler is fixed.",
      "resolution": "A resource type this deployment registered delegates to an external handler, and that handler did not answer. The template is not at fault, so re-deploying it unchanged will fail identically — the deployment operator has to fix the handler (`meta.resource_type` names the type, `meta.request_type` the operation it failed on).",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#formation_handler_failed"
    },
    {
      "code": "FORMATION_INVALID_METADATA",
      "http_status": 400,
      "description": "The formation-level `metadata` field contains a `sub`/`param`/`ref`/`ref_attr` substitution expression. That field is a static annotation bag and is never resolved; put deploy-time substitutions in the template top-level `metadata` block instead.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#formation_invalid_metadata"
    },
    {
      "code": "FORMATION_MISSING_PARAMETERS",
      "http_status": 400,
      "description": "The formation template declares one or more required parameters (no default, not satisfied by use_previous_value) that were not supplied or were provided as an empty string.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#formation_missing_parameters"
    },
    {
      "code": "FORMATION_REPLACE_CLEANUP_FAILED",
      "http_status": 500,
      "description": "A deploy replaced a resource — the handler answered a new `physical_resource_id` — and the superseded resource could not be deleted, so it is still live while the formation's ledger already points at the replacement. The deploy itself succeeded: the desired state is realised, and this is carried on the formation (and on its operation) rather than thrown, so it never appears as a response status. `meta.failures` names each un-deleted resource as `{ logical_id, resource_type, physical_resource_id, error }`. Each one stays on the formation as pending cleanup and is retried on the next deploy and on teardown; resolve whatever refused the delete and deploy again.",
      "resolution": "Retry with backoff. If it persists, the server log carries the detail the response deliberately omits.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#formation_replace_cleanup_failed"
    },
    {
      "code": "FORMATION_RESOURCE_TYPE_UNREGISTERED",
      "http_status": 409,
      "description": "The formation holds a resource whose type the deployment no longer registers, so the platform has no handler to act on it. `meta.resource_type` names the type.",
      "resolution": "Register the resource type again so its handler can act on the resource, or remove the resource outside the formation.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#formation_resource_type_unregistered"
    },
    {
      "code": "GENERATION_ALREADY_IN_PROGRESS",
      "http_status": 409,
      "description": "A generation is already in progress for this session. Wait for it to complete before starting a new one.",
      "resolution": "A generation is already running for this target. Poll it to completion, or cancel it, before starting another.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#generation_already_in_progress"
    },
    {
      "code": "GENERATION_CONTENT_UNAVAILABLE",
      "http_status": 409,
      "description": "The generation's content was never stored (the agent or project runs with trace_content_mode 'none') or has since been purged, so the turn cannot be replayed or curated.",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#generation_content_unavailable"
    },
    {
      "code": "GENERATION_FAILED",
      "http_status": 500,
      "description": "An unexpected error occurred during agent generation. Check the trace for details.",
      "resolution": "Retry with backoff. If it persists, the server log carries the detail the response deliberately omits.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#generation_failed"
    },
    {
      "code": "GENERATION_NOT_AWAITING_TOOL_OUTPUTS",
      "http_status": 409,
      "description": "The generation is not paused on client tool calls: it never paused, or its outputs were already submitted and it resumed. Tool outputs are accepted once per pause.",
      "resolution": "Read the generation for its current status. A generation that pauses again answers `requires_action` with new tool call ids; submit outputs for those.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#generation_not_awaiting_tool_outputs"
    },
    {
      "code": "GENERATION_NOT_COMPLETED",
      "http_status": 409,
      "description": "The generation has not completed, so it has no finished turn: it cannot be curated into a dataset item, and an eval item whose generation settled in another status (a `requires_action` pause, for one) is recorded with this code rather than scored. `meta.status` is the status it settled in.",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#generation_not_completed"
    },
    {
      "code": "GENERATION_NOT_FOUND",
      "http_status": 404,
      "description": "The generation does not exist or is not accessible to the caller.",
      "resolution": "Check the id and the project the credential can see, then retry. Listing the collection confirms whether the resource exists.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#generation_not_found"
    },
    {
      "code": "GUARDRAIL_HAS_REFERENCES",
      "http_status": 409,
      "description": "The guardrail is still attached to one or more tools, agents, or projects (`guardrail_ids`) and cannot be deleted. Detach every reference first (requires guardrails:DetachGuardrail). The error meta lists the referencing resources by scope.",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#guardrail_has_references"
    },
    {
      "code": "GUARDRAIL_NOT_FOUND",
      "http_status": 400,
      "description": "A guardrail referenced by a `guardrail_ids` attachment does not exist in the project.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#guardrail_not_found"
    },
    {
      "code": "HOOK_INVALID_JSON",
      "http_status": 400,
      "description": "The inbound hook request body is not valid JSON.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#hook_invalid_json"
    },
    {
      "code": "HOOK_PAYLOAD_TOO_LARGE",
      "http_status": 413,
      "description": "The inbound hook request body exceeds the 1 MiB limit.",
      "resolution": "The payload exceeds the accepted size. Send less in one request, or use the upload flow for large bodies.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#hook_payload_too_large"
    },
    {
      "code": "IDEMPOTENCY_KEY_REUSED",
      "http_status": 409,
      "description": "The idempotency key is already claimed by a run, generation, session message or task transition sent from a different request. A key names one request, so a caller that changed the body and kept the key has a bug; send the new request under a new key, or repeat the original body to replay what the key already names.",
      "resolution": "Send the changed request under a new `idempotency_key`; repeating the original body under this key replays what it already names.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#idempotency_key_reused"
    },
    {
      "code": "INGESTION_CALLBACK_CONFLICT",
      "http_status": 409,
      "description": "The document is no longer awaiting this conversion attempt — it already completed, timed out, or was superseded by a re-ingest.",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#ingestion_callback_conflict"
    },
    {
      "code": "INGESTION_CALLBACK_INVALID_TOKEN",
      "http_status": 401,
      "description": "The ingestion-callback token is missing, malformed, expired, or does not match the target document.",
      "resolution": "Authenticate the request: send a valid bearer token or project API key in the `Authorization` header.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#ingestion_callback_invalid_token"
    },
    {
      "code": "INGESTION_FAILED",
      "http_status": 500,
      "description": "Recorded on a document, never returned by a request: its ingestion failed for a reason no more specific code names. The message carries the failure.",
      "resolution": "Read the message for the cause, fix the file or its ingestion rule, and ingest the document again.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#ingestion_failed"
    },
    {
      "code": "INGESTION_RULE_GLOB_CONFLICT",
      "http_status": 409,
      "description": "An ingestion rule for this content_type_glob already exists in the project.",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#ingestion_rule_glob_conflict"
    },
    {
      "code": "INGESTION_RULE_VALIDATION_FAILED",
      "http_status": 400,
      "description": "The ingestion rule configuration is invalid (e.g. tool_id and agent_id are both set or both missing, the converter tool is a client tool, a soat/mcp converter tool is missing an action, content_type_glob is not a valid MIME type glob, or preset_parameters contains the reserved key \"file\" or \"callback\").",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#ingestion_rule_validation_failed"
    },
    {
      "code": "INGESTION_TIMEOUT",
      "http_status": 500,
      "description": "Recorded on a document, never returned by a request: its ingestion made no progress within `INGESTION_STALL_TIMEOUT_MS` (five minutes by default), so the next read marked it failed.",
      "resolution": "Ingest the document again. A large file or a busy worker can outlast the window; raise `INGESTION_STALL_TIMEOUT_MS` when it does so repeatedly.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#ingestion_timeout"
    },
    {
      "code": "INTERNAL_ERROR",
      "http_status": 500,
      "description": "An unhandled server-side failure. The message is always the constant \"Internal Server Error\" — the underlying exception is logged, never returned, so this error carries no detail a caller can act on beyond retrying.",
      "resolution": "Retry with backoff. The underlying exception is logged server-side and deliberately never forwarded, so the response carries nothing further to act on.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#internal_error"
    },
    {
      "code": "INVALID_CRON_EXPRESSION",
      "http_status": 400,
      "description": "The cron expression is invalid. Triggers require a strict 5-field cron expression evaluated in UTC.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#invalid_cron_expression"
    },
    {
      "code": "INVALID_EVENT_PATTERN",
      "http_status": 400,
      "description": "The event pattern is invalid. An event trigger subscribes with '*', 'prefix.*', or an exact event name, and a pattern in a platform namespace must match a registered event.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#invalid_event_pattern"
    },
    {
      "code": "INVALID_OUTPUT_SCHEMA",
      "http_status": 400,
      "description": "The agent output_schema is invalid — it must be a JSON Schema object.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#invalid_output_schema"
    },
    {
      "code": "INVALID_TEMPLATE_TOKEN",
      "http_status": 400,
      "description": "A {{...}} double-curly token was found that is not a {{secret:sec_...}} or {{context:<key>}} reference, or a {{context:<key>}} token was found outside execute.headers / mcp.headers. Double curly braces are reserved for those two reference kinds; use single braces ({param}) for URL path parameters.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#invalid_template_token"
    },
    {
      "code": "INVALID_TOOL_CONTEXT_KEY",
      "http_status": 400,
      "description": "A tool_context key cannot be used as an HTTP header name. Keys are forwarded verbatim as <prefix><key> headers, where the prefix is the deployment's SOAT_HEADER_PREFIX followed by Context- (X-Soat-Context- by default), so a key may only contain letters, digits and the characters !#$%&'*+-.^_`|~, and two keys must not map to the same header name (header names are case-insensitive).",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#invalid_tool_context_key"
    },
    {
      "code": "LITERAL_CREDENTIAL",
      "http_status": 400,
      "description": "A tool definition carries a credential as a literal value: a credential-named header, a secret field under execute.auth, or a credential-named query parameter in a url. Store it as a secret and write a {{secret:sec_...}} reference (or a {{context:<key>}} reference in a header) instead.",
      "resolution": "Create the value with `POST /secrets` and write `{{secret:<secret_id>}}` where the literal was (for example `Authorization: Bearer {{secret:sec_...}}`); `meta.paths` names every field to change.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#literal_credential"
    },
    {
      "code": "MCP_TOOL_ERROR",
      "http_status": 502,
      "description": "An mcp-type tool call reached the MCP server and came back a failure: a JSON-RPC `error` member, or a result the server flagged `isError`. The error `meta` carries the tool name and the server URL. Distinct from `TOOL_HTTP_ERROR`, which is the transport itself refusing the call.",
      "resolution": "The MCP server answered the call with a failure rather than a result — `meta.mcp_tool` names the tool and `meta.mcp_url` the server. The message carries what the server said; fix the arguments or the server-side condition it names, then retry. The call reached the server, so this is not a connectivity or allowlist problem.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#mcp_tool_error"
    },
    {
      "code": "MEMORY_ALREADY_INVALIDATED",
      "http_status": 409,
      "description": "The memory no longer holds — a retraction or a supersede already invalidated it — so there is nothing to retract. `meta.memory_id` names it; read it by id to see which.",
      "resolution": "The fact is already out of every read. Read the memory by id to see whether a supersede replaced it, and retract the memory that replaced it if that is the one that no longer holds.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#memory_already_invalidated"
    },
    {
      "code": "MEMORY_RULE_VALIDATION_FAILED",
      "http_status": 400,
      "description": "The memory rule configuration is invalid (e.g. agent_id and tool_id are both set, `on` is not a supported event, the built-in extractor is bound to conversation_messages.generated, an extractor override is combined with a handler, or source_agent_ids is not an array of agent ids).",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#memory_rule_validation_failed"
    },
    {
      "code": "MEMORY_STORE_NOT_FOUND",
      "http_status": 400,
      "description": "A referenced memory store does not exist.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#memory_store_not_found"
    },
    {
      "code": "MISSING_TOOL_CONTEXT_KEY",
      "http_status": 400,
      "description": "A tool header references a {{context:<key>}} token whose key is not present in the tool_context for this call. The call is failed rather than sending the header with an empty value.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#missing_tool_context_key"
    },
    {
      "code": "MODEL_LISTING_FAILED",
      "http_status": 502,
      "description": "The provider rejected the model listing request, or answered it with something other than JSON. The provider's own status and message are carried in the error message.",
      "resolution": "An upstream dependency failed rather than this server itself. Retry with backoff and check that dependency.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#model_listing_failed"
    },
    {
      "code": "MODEL_LISTING_UNSUPPORTED",
      "http_status": 400,
      "description": "The AI provider type cannot enumerate the models it can run. Azure lists deployments an operator named rather than models, and Ollama lists whatever was pulled onto that host, so neither answers the question.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#model_listing_unsupported"
    },
    {
      "code": "MODEL_NOT_PRICED",
      "http_status": 409,
      "description": "The project runs with `require_priced_model` and no price-book row covers a billable token component of the model this generation would run on, so the spend it would incur could not be measured. The check runs before the provider is called: nothing is sent, spent or metered. `meta.unpriced_rows` names each `(provider, model, component)` to price. An agent bound to a model route is held to every target it may fail over to, not just the first. Price the rows, or clear `require_priced_model` on the project to accept unmeasurable spend.",
      "resolution": "Add price book rows for every `(provider, model, component)` in `meta.unpriced_rows` — globally with `PUT /api/v1/usage/prices`, or for one provider instance with `PUT /api/v1/ai-providers/{ai_provider_id}/prices`. To run unpriced models again, set `require_priced_model` to `false` with `PATCH /api/v1/projects/{project_id}`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#model_not_priced"
    },
    {
      "code": "MODEL_ROUTE_HAS_DEPENDENTS",
      "http_status": 409,
      "description": "The model route is referenced by one or more agents, or is a project's default_model_route_id, and cannot be deleted. Repoint or delete the referencing consumers first; the error meta reports the counts and a sample of agent IDs.",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#model_route_has_dependents"
    },
    {
      "code": "MODEL_ROUTE_NOT_FOUND",
      "http_status": 400,
      "description": "A referenced model route does not exist in the project.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#model_route_not_found"
    },
    {
      "code": "NAME_CONFLICT",
      "http_status": 409,
      "description": "A resource with this name already exists in the project. Use a different name.",
      "resolution": "A resource with this name already exists in the project. Pick another name, or update the existing resource instead of creating a second one.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#name_conflict"
    },
    {
      "code": "NOT_IMPLEMENTED",
      "http_status": 501,
      "description": "The request is well-formed but names an option this API version does not implement.",
      "resolution": "The operation exists in the contract but is not implemented on this deployment. Retrying will not change the outcome.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#not_implemented"
    },
    {
      "code": "NO_ACTIVE_RELEASE",
      "http_status": 409,
      "description": "The agent has no active release to promote or abort. Set one with PUT /agents/{agent_id}/release first.",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#no_active_release"
    },
    {
      "code": "ON_BEHALF_OF_INVALID",
      "http_status": 400,
      "description": "The `On-Behalf-Of` header is not an unexpired tool assertion this deployment signed (`meta.reason: unverified`), or the request is not made with an API key scoped to the project the assertion names (`meta.reason: project`).",
      "resolution": "Forward the tool assertion of the call being served unchanged, within its lifetime, with the API key of the project it names; or drop the header to write as the key.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#on_behalf_of_invalid"
    },
    {
      "code": "ORCHESTRATION_CYCLE_DETECTED",
      "http_status": 422,
      "description": "The orchestration graph contains a cycle. Cycles are not supported.",
      "resolution": "The graph has a cycle, so no topological order exists. Break the cycle named in `meta` — a loop belongs in a workflow, not a DAG.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#orchestration_cycle_detected"
    },
    {
      "code": "ORCHESTRATION_DISPATCH_FAILED",
      "http_status": 422,
      "description": "A workflow on_enter dispatch's orchestration run settled in a non-success terminal status (failed, cancelled, or expired).",
      "resolution": "The request was accepted and then could not be carried out. The failure is in the work, not the request shape — read `meta` and the trace for which step failed before retrying.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#orchestration_dispatch_failed"
    },
    {
      "code": "ORCHESTRATION_HUMAN_NODE_MISMATCH",
      "http_status": 400,
      "description": "The specified node is not the active human node waiting for input.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#orchestration_human_node_mismatch"
    },
    {
      "code": "ORCHESTRATION_MAX_ITERATIONS_EXCEEDED",
      "http_status": 422,
      "description": "The orchestration run exceeded the maximum number of iterations.",
      "resolution": "The request was accepted and then could not be carried out. The failure is in the work, not the request shape — read `meta` and the trace for which step failed before retrying.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#orchestration_max_iterations_exceeded"
    },
    {
      "code": "ORCHESTRATION_NESTED_RUN_FAILED",
      "http_status": 422,
      "description": "A `loop` / `sub_orchestration` child run settled in a non-success terminal status (failed, cancelled, or expired) carrying no code of its own, so the node that started it failed too. A child that carries a code fails its parent under that code instead, so the cause reaches the run a caller reads. Matches ORCHESTRATION_DISPATCH_FAILED, the same rule for a workflow on_enter dispatch's run.",
      "resolution": "The request was accepted and then could not be carried out. The failure is in the work, not the request shape — read `meta` and the trace for which step failed before retrying.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#orchestration_nested_run_failed"
    },
    {
      "code": "ORCHESTRATION_NODE_FAILED",
      "http_status": 422,
      "description": "A node in the orchestration run failed to execute.",
      "resolution": "The request was accepted and then could not be carried out. The failure is in the work, not the request shape — read `meta` and the trace for which step failed before retrying.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#orchestration_node_failed"
    },
    {
      "code": "ORCHESTRATION_NOT_FOUND",
      "http_status": 404,
      "description": "The orchestration does not exist or is not accessible.",
      "resolution": "Check the id and the project the credential can see, then retry. Listing the collection confirms whether the resource exists.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#orchestration_not_found"
    },
    {
      "code": "ORCHESTRATION_POLL_EXHAUSTED",
      "http_status": 422,
      "description": "A poll node reached its attempt limit without its exit condition becoming true (only raised when fail_on_timeout is set).",
      "resolution": "The request was accepted and then could not be carried out. The failure is in the work, not the request shape — read `meta` and the trace for which step failed before retrying.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#orchestration_poll_exhausted"
    },
    {
      "code": "ORCHESTRATION_RUN_DEPTH_LIMIT",
      "http_status": 409,
      "description": "Starting the next `loop` / `sub_orchestration` child run would nest past the depth bound, so it was refused. This bounds a cycle no intra-graph validator can see — a graph whose `sub_orchestration` node names itself, directly or through a cycle of two graphs — which the orchestration cycle validator (intra-graph, and excluding loop nodes deliberately) cannot detect. The bound is the smaller of MAX_ORCHESTRATION_RUN_DEPTH (default 10) and the project's `max_orchestration_run_depth`; the error meta names the depth reached, the limit, and which of the two set it.",
      "resolution": "Nesting is recursing: follow `parent_orchestration_run_id` up from the failed run to find the `sub_orchestration` (or `loop`) node that names a graph already in the chain, and repoint it. If the composition is legitimately this deep, raise the project bound with `PATCH /api/v1/projects/{project_id}` (`max_orchestration_run_depth`) — `meta.limit_source` says whether the project or the deployment set the number that refused it.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#orchestration_run_depth_limit"
    },
    {
      "code": "ORCHESTRATION_RUN_NOT_AWAITING_INPUT",
      "http_status": 409,
      "description": "The orchestration run is not awaiting input.",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#orchestration_run_not_awaiting_input"
    },
    {
      "code": "ORCHESTRATION_RUN_NOT_CANCELLABLE",
      "http_status": 409,
      "description": "The orchestration run is already in a terminal state and cannot be cancelled.",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#orchestration_run_not_cancellable"
    },
    {
      "code": "ORCHESTRATION_RUN_NOT_FOUND",
      "http_status": 404,
      "description": "The orchestration run does not exist or is not accessible.",
      "resolution": "Check the id and the project the credential can see, then retry. Listing the collection confirms whether the resource exists.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#orchestration_run_not_found"
    },
    {
      "code": "ORCHESTRATION_RUN_NOT_PAUSABLE",
      "http_status": 409,
      "description": "The orchestration run has already settled, so there is nothing left to pause. Unlike cancel, a pause keeps the run's last checkpoint and the existing resume route re-drives it from there — so it only applies to a run that is queued, running, sleeping or awaiting input.",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#orchestration_run_not_pausable"
    },
    {
      "code": "ORCHESTRATION_RUN_PAUSED",
      "http_status": 409,
      "description": "An operator pause is in force on the run, so the requested action was refused. An operator pause has no payload to supply, and a pause standing behind a human or approval node must not be lifted by satisfying it — resume the run first, then submit.",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#orchestration_run_paused"
    },
    {
      "code": "ORCHESTRATION_VALIDATION_FAILED",
      "http_status": 400,
      "description": "The orchestration graph is invalid (e.g. a dangling edge, a node missing a required field, a cycle, or an input_mapping that references a state key no upstream node writes).",
      "resolution": "The orchestration graph is not runnable as declared. `meta` names the failing node or edge; `POST /api/v1/orchestrations/{orchestration_id}/validate` reports every problem at once.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#orchestration_validation_failed"
    },
    {
      "code": "OUTPUT_SCHEMA_STREAMING_UNSUPPORTED",
      "http_status": 400,
      "description": "Streaming generation does not support output_schema. Set stream to false, or remove output_schema from the agent/request.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#output_schema_streaming_unsupported"
    },
    {
      "code": "OUTPUT_SCHEMA_VALIDATION_FAILED",
      "http_status": 502,
      "description": "The model returned an object that does not satisfy the agent output_schema (or was not valid JSON at all). Upstream-caused like AI_PROVIDER_ERROR: the request was well-formed, the model output was not.",
      "resolution": "The model answered and the answer does not satisfy `output_schema` — the violated field is named in the message. Retrying the same request bills a second call to reach the same answer; loosen the schema, or make the instructions name the shape the model keeps missing.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#output_schema_validation_failed"
    },
    {
      "code": "PDF_PARSE_FAILED",
      "http_status": 400,
      "description": "The uploaded file could not be parsed as a PDF. Ensure the file is a valid PDF document.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#pdf_parse_failed"
    },
    {
      "code": "PIPELINE_DEPTH_EXCEEDED",
      "http_status": 422,
      "description": "The pipeline tool exceeded the maximum nested execution depth (pipelines calling pipelines).",
      "resolution": "The request was accepted and then could not be carried out. The failure is in the work, not the request shape — read `meta` and the trace for which step failed before retrying.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#pipeline_depth_exceeded"
    },
    {
      "code": "PIPELINE_INVALID_STEP",
      "http_status": 400,
      "description": "The pipeline tool configuration is invalid (e.g. no steps and no `output`, a duplicate or malformed step id, a missing tool reference, a forward reference to a later step, or a step that targets a client tool).",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#pipeline_invalid_step"
    },
    {
      "code": "PIPELINE_STEP_FAILED",
      "http_status": 422,
      "description": "A step in the pipeline tool failed to execute.",
      "resolution": "The request was accepted and then could not be carried out. The failure is in the work, not the request shape — read `meta` and the trace for which step failed before retrying.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#pipeline_step_failed"
    },
    {
      "code": "PLAYBOOK_AUTHOR_UNAVAILABLE",
      "http_status": 409,
      "description": "The case's playbook version has no author a node can run as: the user or API key that wrote it no longer exists, or it was written with a trigger or OAuth token, which carry their boundary in the token.",
      "resolution": "Write the playbook's definition again as a user or API key that can start its executors; cases created on that version run as them.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#playbook_author_unavailable"
    },
    {
      "code": "PLAYBOOK_CASE_BUSY",
      "http_status": 409,
      "description": "An upgrade of a case while one of its executions is running: it would settle against nodes the new version may not have. `meta.executions` names each by `id` and `node`.",
      "resolution": "Wait for the executions `meta.executions` names to settle — close a workflow task, or let an orchestration run end — then retry the upgrade.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#playbook_case_busy"
    },
    {
      "code": "PLAYBOOK_CASE_NOT_PAUSED",
      "http_status": 409,
      "description": "The case carries no pause, so there is nothing to resume.",
      "resolution": "Nothing to do: the case is already running.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#playbook_case_not_paused"
    },
    {
      "code": "PLAYBOOK_CASE_PAUSED",
      "http_status": 409,
      "description": "The case is paused, so none of its nodes starts: neither the cascade nor a run of one node. Executions already in flight settle. Resume the case first.",
      "resolution": "Resume the case with `POST /api/v1/playbook-cases/{case_id}/resume`, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#playbook_case_paused"
    },
    {
      "code": "PLAYBOOK_EXECUTION_FAILED",
      "http_status": 422,
      "description": "A node's executor settled without a value the node can hold as its output: an agent that returned neither text nor an object, a decision or orchestration run that failed, or a task closed without a payload. Recorded on the execution's `error`, never answered by a request.",
      "resolution": "Read the execution's `error` and the run it names in `run_id`, fix the executor, and run the node again.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#playbook_execution_failed"
    },
    {
      "code": "PLAYBOOK_EXECUTION_INTERRUPTED",
      "http_status": 500,
      "description": "Recorded on an execution, never returned by a request: the process running the node's agent, tool or decider stopped before it settled. It is not run again on its own, so a call with side effects never runs twice; run the node again.",
      "resolution": "Run the node again with `POST /api/v1/playbook-cases/{case_id}/nodes/{node}/run` once whatever its executor called is known not to need undoing.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#playbook_execution_interrupted"
    },
    {
      "code": "PLAYBOOK_EXECUTOR_FORBIDDEN",
      "http_status": 403,
      "description": "The playbook version's author may not start an executor the definition names. Refused when the version is written, and again when a node runs if the author's permission was removed since. `meta` names the `node` and the IAM `action`.",
      "resolution": "Grant the author the start action `meta.action` names on the executor, or have someone who holds it write the playbook's definition, which makes them the author of the new version.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#playbook_executor_forbidden"
    },
    {
      "code": "PLAYBOOK_EXPORT_FAILED",
      "http_status": 422,
      "description": "Recorded on an export, never returned by a request: the transformation's tool failed, or answered no file. A tool answers a file with `execute.response_mode: base64`.",
      "resolution": "Read the export's `error`, make the transformation's tool answer a file (`execute.response_mode: base64`), and export the node again.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#playbook_export_failed"
    },
    {
      "code": "PLAYBOOK_EXPORT_FORMAT_MISMATCH",
      "http_status": 422,
      "description": "Recorded on an export, never returned by a request: the transformation's tool answered a file whose content type is not its `format`'s. `meta` carries both.",
      "resolution": "Make the tool answer the content type of the transformation's `format`, or declare the format it produces, and export the node again.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#playbook_export_format_mismatch"
    },
    {
      "code": "PLAYBOOK_EXPORT_INTERRUPTED",
      "http_status": 500,
      "description": "Recorded on an export, never returned by a request: the process rendering it stopped before it settled. It is not rendered again on its own; export the node again.",
      "resolution": "Export the node again with `POST /api/v1/playbook-cases/{case_id}/nodes/{node}/exports`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#playbook_export_interrupted"
    },
    {
      "code": "PLAYBOOK_HAS_CASES",
      "http_status": 409,
      "description": "The playbook has cases and cannot be deleted; a case is the record of what was filled against it.",
      "resolution": "Delete the playbook’s cases first, or keep the playbook and stop creating cases from it.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#playbook_has_cases"
    },
    {
      "code": "PLAYBOOK_INPUT_CONFLICT",
      "http_status": 409,
      "description": "An input write's `expected_revision` is not the field's current revision: someone wrote it since it was read. `meta.conflicts` lists each field with both revisions; nothing in the batch was written.",
      "resolution": "Re-read the case, decide each conflicting field against its current value, and retry with the revisions `meta.conflicts` names.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#playbook_input_conflict"
    },
    {
      "code": "PLAYBOOK_INPUT_INVALID",
      "http_status": 400,
      "description": "An input write names a node or input the case's playbook version does not declare, an input that reads another node, or a value its input's schema refuses.",
      "resolution": "Read the case's `nodes` for the inputs its version declares and which of them are filled by a person; correct the value to its input's schema.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#playbook_input_invalid"
    },
    {
      "code": "PLAYBOOK_NODE_NOT_CONFIRMABLE",
      "http_status": 409,
      "description": "The node cannot be confirmed: it is not a `confirm` node, or a required input is unset or reads a node that is not `done`. `meta` carries the `state`, `missing` and `blocked_by`.",
      "resolution": "Read the case: confirm only a `confirm` node, after filling what `missing` names and once the nodes `blocked_by` names are `done`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#playbook_node_not_confirmable"
    },
    {
      "code": "PLAYBOOK_NODE_NOT_EXPORTABLE",
      "http_status": 409,
      "description": "An export of the latest revision of a node that is not `done`: it has no output yet, or its output is `stale`, `running` or `failed`. `meta` carries the `state`. Name a `revision` to export an earlier output.",
      "resolution": "Wait for the node to settle, or run it again if it `failed`; to export an earlier output, name its `revision` from the case's entries.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#playbook_node_not_exportable"
    },
    {
      "code": "PLAYBOOK_NODE_NOT_RUNNABLE",
      "http_status": 409,
      "description": "The node cannot run now: it is a `confirm` node, a required input is unset or reads a node that is not `done`, or it is already `running` or `waiting` on the task or run it started. `meta` carries the `state`, `missing` and `blocked_by`.",
      "resolution": "Read the case: fill what `missing` names, wait for the nodes `blocked_by` names, or confirm a `confirm` node instead of running it. A `running` node settles on its own; a `waiting` one settles when the task or run its `run` names closes or ends.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#playbook_node_not_runnable"
    },
    {
      "code": "PLAYBOOK_SELF_WRITE",
      "http_status": 403,
      "description": "A write into a case from the work it is running: a run-as credential minted for the case, for one of its executions in flight, or for the task or orchestration run one started. An executor's output reaches its case only as the node's output.",
      "resolution": "Return the value as the executor's result instead: it becomes the node's output, which the nodes reading it take as input.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#playbook_self_write"
    },
    {
      "code": "PLAYBOOK_VALIDATION_FAILED",
      "http_status": 400,
      "description": "The playbook definition is invalid: a duplicate node or input, an input reading a missing node or field, an executor on a node that may not have one or missing from one that must, transformations on a non-final node, two transformations of one name on a node, or a cycle. `meta.problems` lists every one.",
      "resolution": "Fix every problem `meta.problems` lists and retry. `POST /api/v1/playbooks/validate` answers the same check without writing.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#playbook_validation_failed"
    },
    {
      "code": "POLICY_NOT_FOUND",
      "http_status": 400,
      "description": "A referenced policy does not exist.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#policy_not_found"
    },
    {
      "code": "PROJECT_DEFAULT_ROUTE_INHERITED",
      "http_status": 409,
      "description": "A project's default_model_route_id cannot be cleared while consumers that bind neither an AI provider nor a model route inherit it — clearing it would leave them with no resolvable model. Repointing the default to another route is always allowed; the error meta reports the count and a sample of inheriting resource IDs.",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#project_default_route_inherited"
    },
    {
      "code": "PROJECT_HAS_DEPENDENTS",
      "http_status": 409,
      "description": "The project has one or more dependent resources (agents, ai providers, tools, etc.) and cannot be deleted. Use force=true to delete dependents as well.",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#project_has_dependents"
    },
    {
      "code": "PROJECT_NOT_PAUSED",
      "http_status": 409,
      "description": "The project carries no pause, so there is nothing to resume.",
      "resolution": "Nothing to do: the project is already running. Read `paused_at` on `GET /api/v1/projects/{project_id}` before resuming.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#project_not_paused"
    },
    {
      "code": "PROJECT_PAUSED",
      "http_status": 409,
      "description": "The project is paused, so nothing new starts in it: no generation, chat completion, tool call, orchestration run, eval run, decision or trigger firing, and no resume of a run or task the pause holds. Reads and configuration writes still work. `meta` carries `project_id`, `paused_at` and `pause_reason`.",
      "resolution": "Resume the project with `POST /api/v1/projects/{project_id}/resume` once whatever paused it is resolved; `meta.pause_reason` says why it was paused. Nothing is queued while paused — retry the request after resuming.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#project_paused"
    },
    {
      "code": "PROMOTION_GATE_UNMET",
      "http_status": 409,
      "description": "The release's promotion_gate has no passing eval run against the canary version. Run the eval with agent_version pinned to the canary, or abort the rollout.",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#promotion_gate_unmet"
    },
    {
      "code": "PUBLIC_SHARES_DISABLED",
      "http_status": 403,
      "description": "A share with `grantee: \"*\"` offers the resource to every project, which this deployment does not allow. Name one grantee project, or set `SHARES_ALLOW_PUBLIC=true` on the server.",
      "resolution": "Create the share with a project id as `grantee`, or ask the operator to set `SHARES_ALLOW_PUBLIC=true`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#public_shares_disabled"
    },
    {
      "code": "QUEUE_DRIVER_MISCONFIGURED",
      "http_status": 500,
      "description": "The orchestration queue driver is not configured correctly — an unknown ORCHESTRATION_QUEUE_DRIVER, or a missing required variable for the selected driver (e.g. ORCHESTRATION_QUEUE_SQS_QUEUE_URL for sqs).",
      "resolution": "Retry with backoff. If it persists, the server log carries the detail the response deliberately omits.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#queue_driver_misconfigured"
    },
    {
      "code": "QUOTA_CONFLICT",
      "http_status": 409,
      "description": "A quota with the same (project, scope, scope_ref, metric, window) already exists. The all-enforce precedence rule makes duplicates pure redundancy, so a duplicate is rejected instead of stored.",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#quota_conflict"
    },
    {
      "code": "QUOTA_EXCEEDED",
      "http_status": 429,
      "description": "An enforced quota has been exceeded for the request scope. The response carries a `Retry-After` header (seconds until the window resets) and a `meta` block naming the breached quota, metric, limit, window, and reset time.",
      "resolution": "Wait until the window resets — `Retry-After` (seconds) and `meta.resets_at` both carry the time — or raise the quota with `PATCH /api/v1/quotas/{quota_id}`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#quota_exceeded"
    },
    {
      "code": "QUOTA_STORAGE_EXCEEDED",
      "http_status": 409,
      "description": "An enforced `storage_bytes` quota is exceeded: the project's stored footprint — files, document chunks (text and vector) and memories — is already over the byte limit, and the write would have added to it. No `Retry-After` is sent, and the refusal is a 409 rather than a 429, because a stock is not a rate: no window reset clears it and waiting changes nothing. The error meta carries `current_bytes` (the last daily snapshot plus the request's own delta) beside `limit`, so the caller knows how much to delete. Raised at the corpus write paths — file upload/create, document create, document ingest and re-ingest, memory create.",
      "resolution": "Delete stored content — files, documents, or memories — until the project is back under the cap; `meta.current_bytes` and `meta.limit` say by how much. Waiting does not help: a storage quota caps a stored total, not a rate. Alternatively raise the cap with `PATCH /api/v1/quotas/{quota_id}`, or switch it to `monitor` mode to stop blocking while you measure.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#quota_storage_exceeded"
    },
    {
      "code": "QUOTA_UNENFORCEABLE",
      "http_status": 409,
      "description": "An enforced `cost_usd` quota with `on_unpriced: \"block\"` (the default) cannot be evaluated: the current window holds a pricing blackout — several metered events, none of them priced — so the aggregate is `0` however much was actually spent. The cap refuses the generation rather than waving through spend it cannot measure. No `Retry-After` is sent — the window resetting changes nothing; configure pricing for the models in use, or set the quota's `on_unpriced` to `\"allow\"` to accept unmeasurable spend explicitly.",
      "resolution": "Add price book entries covering the models this project runs (`POST /api/v1/prices`), so the cost quota has something to aggregate. To accept unmeasurable spend instead, set `on_unpriced: \"allow\"` on the quota with `PATCH /api/v1/quotas/{quota_id}` (or switch it to `monitor` mode to stop blocking entirely).",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#quota_unenforceable"
    },
    {
      "code": "REQUEST_REJECTED",
      "http_status": 400,
      "description": "The HTTP framework rejected the request before it reached a handler — a payload over the size limit, an unsupported method, a malformed request line. The accompanying message carries the specific reason, and the response status is the one the framework chose rather than this default.",
      "resolution": "The HTTP layer rejected the request before it reached a route — method, content type, or size. The message names the reason.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#request_rejected"
    },
    {
      "code": "RESERVED_PATH",
      "http_status": 400,
      "description": "The path is under '/.system/', which is reserved for files and documents the platform writes on your behalf. Choose a path outside it.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#reserved_path"
    },
    {
      "code": "RESERVED_TAG_KEY",
      "http_status": 400,
      "description": "The tag key is reserved: keys starting with 'system.' are written by the platform to record which conversation, actor, agent and role a row came from, and cannot be set by a caller.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#reserved_tag_key"
    },
    {
      "code": "RESOURCE_NOT_FOUND",
      "http_status": 404,
      "description": "The requested resource does not exist or is not accessible.",
      "resolution": "Check the id, and check that the credential can see the project that owns the resource — a resource in another project is indistinguishable from one that does not exist. List the collection to confirm.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#resource_not_found"
    },
    {
      "code": "SECRET_HAS_DEPENDENTS",
      "http_status": 409,
      "description": "The secret is referenced by one or more AI providers and cannot be deleted. Use force=true to delete dependents as well.",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#secret_has_dependents"
    },
    {
      "code": "SECRET_NOT_DECRYPTABLE",
      "http_status": 500,
      "description": "A stored trigger or webhook secret could not be decrypted — SECRETS_ENCRYPTION_KEY has changed since it was written. Rotating the secret replaces it; restoring the original key recovers every secret written under it.",
      "resolution": "Retry with backoff. If it persists, the server log carries the detail the response deliberately omits.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#secret_not_decryptable"
    },
    {
      "code": "SECRET_NOT_FOUND",
      "http_status": 400,
      "description": "A secret referenced by a {{secret:...}} token does not exist in this project.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#secret_not_found"
    },
    {
      "code": "SESSION_CLOSED",
      "http_status": 409,
      "description": "The session is closed and does not accept new messages or generation requests. Open a new session to continue.",
      "resolution": "The session is closed and accepts no further messages. Open a new one, or fork this one to keep its history.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#session_closed"
    },
    {
      "code": "SESSION_EXPIRED",
      "http_status": 410,
      "description": "The session has expired due to inactivity. Open a new session to continue.",
      "resolution": "Open a new session; an expired one cannot be revived. Raise the agent's session TTL if this happens sooner than the workload needs.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#session_expired"
    },
    {
      "code": "SESSION_NOT_FOUND",
      "http_status": 400,
      "description": "A referenced session does not exist.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#session_not_found"
    },
    {
      "code": "SHARE_CAP_EXCEEDED",
      "http_status": 429,
      "description": "The call reached another project's tool or agent through a share whose `cap` is spent for the current window, so nothing ran and nothing was metered. The response carries a `Retry-After` header, and `meta` names the share, its `calls` and `window`, `resets_at` and `retry_after`.",
      "resolution": "Wait `retry_after` seconds for the share's window to reset, or ask the publisher to raise its cap.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#share_cap_exceeded"
    },
    {
      "code": "SHARE_IN_USE",
      "http_status": 409,
      "description": "The grantee project still names the shared resource. `meta.references` lists each of its resources that does; revoking the acceptance leaves them degraded.",
      "resolution": "Repoint or remove the resources `meta.references` lists, or pass `force=true` to revoke anyway and let them degrade.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#share_in_use"
    },
    {
      "code": "SHARE_REVOKED",
      "http_status": 403,
      "description": "The share was revoked by its publisher, or the publisher revoked this project's acceptance of it. A revoked share accepts nothing and cannot be suspended or resumed; a revoked acceptance refuses a new accept from the same project until the publisher deletes it.",
      "resolution": "A revoked share cannot be used again: ask the publisher for a new share. If the publisher revoked only your acceptance, it must delete that acceptance before you can accept again.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#share_revoked"
    },
    {
      "code": "SINGLE_SESSION_CONFLICT",
      "http_status": 409,
      "description": "An open session already exists for this actor. Use the existing session or close it first.",
      "resolution": "The agent allows one open session per actor. Reuse the session named in `meta.session_id`, or close it first.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#single_session_conflict"
    },
    {
      "code": "SYSTEM_MESSAGE_NOT_ALLOWED",
      "http_status": 400,
      "description": "A `role: \"system\"` entry was supplied in `messages`. System content never travels as a message on any SOAT surface — it goes in the `instructions` field instead — the same name on every surface (a completion request, a Chat, an Agent). Mirrors the AI SDK, whose `allowSystemInMessages` defaults to false because a system entry in a caller-supplied array is a prompt-injection vector.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#system_message_not_allowed"
    },
    {
      "code": "TASK_AUTOMATION_CHAIN_LIMIT",
      "http_status": 409,
      "description": "The task has run too many machine-driven transitions back-to-back with no outside intervention, and the next one was refused. This bounds a cycle composed across modules — a workflow state dispatching work that transitions the task back into that same state — which neither the orchestration cycle validator (intra-graph) nor the workflow itself (where revisiting states is deliberate) can see. Any move by a person, a plain API key, or an approval resolution resets the chain. The ceiling is TASK_AUTOMATION_CHAIN_LIMIT (default 50).",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#task_automation_chain_limit"
    },
    {
      "code": "TASK_AUTOMATION_PROVENANCE_MISSING",
      "http_status": 500,
      "description": "An automation-caused transition was about to be persisted with no recorded cause: principal_id, generation_id, and orchestration_run_id would all be null. This is a writer bug, not a valid degraded record — the transition is rejected instead of being silently written.",
      "resolution": "Retry with backoff. If it persists, the server log carries the detail the response deliberately omits.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#task_automation_provenance_missing"
    },
    {
      "code": "TASK_GUARD_REJECTED",
      "http_status": 400,
      "description": "The transition guard evaluated to false for this task.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#task_guard_rejected"
    },
    {
      "code": "TASK_MIGRATION_CONFLICT",
      "http_status": 409,
      "description": "The task cannot change workflow version now: it is closed, has a transition pending approval (`meta.pending_transition`), or has a dispatch in flight whose routing belongs to the version it was dispatched under.",
      "resolution": "Let the dispatch settle or resolve the pending approval, then migrate again; a closed task stays on its version.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#task_migration_conflict"
    },
    {
      "code": "TASK_MIGRATION_STATE_UNMAPPED",
      "http_status": 400,
      "description": "The task's current state is not declared by the target workflow version and the migration's `state_map` does not map it. `meta.state` names it.",
      "resolution": "Add `state_map: { \"<meta.state>\": \"<a state the target version declares>\" }` to the migration.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#task_migration_state_unmapped"
    },
    {
      "code": "TASK_NOT_FOUND",
      "http_status": 404,
      "description": "The task does not exist or is not accessible.",
      "resolution": "Check the id and the project the credential can see, then retry. Listing the collection confirms whether the resource exists.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#task_not_found"
    },
    {
      "code": "TASK_NOT_PAUSABLE",
      "http_status": 409,
      "description": "The task is closed, so there is no automation left to pause. A workflow has no run object, so an operator pause lands on its instance — the task — and suppresses every state dispatch until it is resumed.",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#task_not_pausable"
    },
    {
      "code": "TASK_NOT_PAUSED",
      "http_status": 409,
      "description": "The task carries no operator pause, so there is nothing to resume. Resuming is only how a pause is lifted; a task that is merely idle is advanced by firing a transition.",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#task_not_paused"
    },
    {
      "code": "TASK_PAYLOAD_INVALID",
      "http_status": 400,
      "description": "The task payload does not satisfy the workflow's payload_schema.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#task_payload_invalid"
    },
    {
      "code": "TASK_STATE_NOT_FOUND",
      "http_status": 400,
      "description": "A task create request's `state`, or a migration's `state_map` target, does not name a declared state of the workflow version. `meta.state` names it.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#task_state_not_found"
    },
    {
      "code": "TASK_TRANSITION_CONFLICT",
      "http_status": 409,
      "description": "A concurrent change made the requested transition invalid from the current state, or the task is already closed.",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#task_transition_conflict"
    },
    {
      "code": "TASK_TRANSITION_NOT_FOUND",
      "http_status": 400,
      "description": "The named transition does not exist in the workflow.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#task_transition_not_found"
    },
    {
      "code": "TEXT_ENCODED_TOOL_CALL",
      "http_status": 502,
      "description": "The model wrote a tool invocation as plain assistant text (e.g. a ```json block containing {\"name\": \"<a bound tool>\", \"arguments\": {…}}) instead of making a structured tool call, so the tool never ran. Upstream-caused like AI_PROVIDER_ERROR: returning that text as the answer would be a silent data-integrity failure, so the generation fails instead.",
      "resolution": "An upstream dependency failed rather than this server itself. Retry with backoff and check that dependency.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#text_encoded_tool_call"
    },
    {
      "code": "TOOL_AUTH_FAILED",
      "http_status": 502,
      "description": "An http-type tool's `execute.auth` credentials could not be turned into a request credential — malformed service account JSON, an unusable private key, or a token endpoint that rejected the assertion. The error `meta` carries the token endpoint's status and body when it responded. Distinct from `TOOL_HTTP_ERROR`, which is the tool's own target rejecting the call.",
      "resolution": "An upstream dependency failed rather than this server itself. Retry with backoff and check that dependency.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#tool_auth_failed"
    },
    {
      "code": "TOOL_CALL_FAILED",
      "http_status": 500,
      "description": "Recorded on a generation transcript's tool result, never returned by a request: a tool call made during the turn failed with an error that carries no code of its own, and the model received the failure as the call's result. `meta` carries the fields the thrown error held (`name`, an HTTP tool's `status`, `url`, `body`, …).",
      "resolution": "Read `meta` for what the tool raised. The turn went on with the failure as the call result, so fix the tool or its target for the next turn.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#tool_call_failed"
    },
    {
      "code": "TOOL_CALL_NOT_SUPPORTED",
      "http_status": 422,
      "description": "This tool type cannot be invoked server-side. Client tools must be executed by the calling client.",
      "resolution": "The request was accepted and then could not be carried out. The failure is in the work, not the request shape — read `meta` and the trace for which step failed before retrying.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#tool_call_not_supported"
    },
    {
      "code": "TOOL_DISPATCH_FAILED",
      "http_status": 422,
      "description": "A tool call was settled by a guardrail before it ran — blocked (class D or a class-B tripwire), or routed to human approval (class C) on a path with nowhere to park. The error `meta` carries the `tool_id` and the `outcome` that settled it. Raised on every dispatch that cannot await sign-off: a direct `POST /tools/{tool_id}/call`, a pipeline step, a trigger firing a tool target, and a workflow on_enter `tool` dispatch. Reach the tool through an agent or an orchestration instead when it is approval-gated: both can park on the approval and resume from it.",
      "resolution": "The request was accepted and then could not be carried out. The failure is in the work, not the request shape — read `meta` and the trace for which step failed before retrying.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#tool_dispatch_failed"
    },
    {
      "code": "TOOL_EGRESS_BLOCKED",
      "http_status": 403,
      "description": "An outbound request the deployment makes to a URL a tenant chose — an http- or mcp-type tool's target, a webhook's `url`, an AI provider's `base_url`, a service-account key file's `token_uri` — names a destination that is not publicly routable: a loopback, private, link-local (cloud metadata), CGNAT or IPv6 ULA address, and the deployment's TOOL_EGRESS_ALLOWED_HOSTS does not list it. Also returned when a hostname resolves to such an address, when a redirect leads to one, when the scheme is not http/https, or when the redirect chain is too long. The error `meta` carries `tool_url` and, when known, the offending `tool_address`. A webhook delivery refused this way is closed rather than retried, with the reason on the delivery row.",
      "resolution": "The deployment only makes outbound requests to publicly routable addresses, and this destination is not one — `meta.tool_url` names it and `meta.tool_address` the address it resolved to. Point the tool, webhook or provider `base_url` at a public host, or have the operator list this destination in TOOL_EGRESS_ALLOWED_HOSTS. It is not a permissions problem: no policy grants it.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#tool_egress_blocked"
    },
    {
      "code": "TOOL_HAS_DEPENDENTS",
      "http_status": 409,
      "description": "The tool is the backend of one or more deciders, or another project has accepted a share of it, and it cannot be deleted. `meta.decider_count` counts the deciders, which block even under `force=true`: delete them or point them at another backend first. `meta.accepted_share_count` counts the accepted shares and `meta.ingestion_rule_count` the ingestion rules of the tool's own project converting with it; both block only until `force=true`, which revokes the shares and leaves the rules naming a converter that is gone.",
      "resolution": "Delete the deciders that name the tool, or point them at another backend with `PATCH /api/v1/deciders/{decider_id}`, then delete the tool. Accepted shares (`meta.accepted_share_count`) are revoked by retrying with `force=true`; ingestion rules (`meta.ingestion_rule_count`) are repointed with `PATCH /api/v1/ingestion-rules/{ingestion_rule_id}`, or left without a converter by `force=true`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#tool_has_dependents"
    },
    {
      "code": "TOOL_HTTP_ERROR",
      "http_status": 502,
      "description": "An http-type tool call returned a non-2xx response. The error `meta` carries the real upstream status code, response body, URL, and method.",
      "resolution": "An upstream dependency failed rather than this server itself. Retry with backoff and check that dependency.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#tool_http_error"
    },
    {
      "code": "TOOL_NOT_FOUND",
      "http_status": 400,
      "description": "A referenced tool does not exist.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#tool_not_found"
    },
    {
      "code": "TOOL_RESPONSE_TOO_LARGE",
      "http_status": 502,
      "description": "An http-type tool with `execute.response_mode: base64` answered with a body over the deployment's ceiling (`TOOL_RESPONSE_MAX_BYTES`, the file upload ceiling by default). The body is refused while it streams, so nothing was buffered. The error `meta` carries `tool_url` and `max_bytes`.",
      "resolution": "The target's file is over this deployment's ceiling (`meta.max_bytes`). Fetch a smaller file, or ask the operator to raise `TOOL_RESPONSE_MAX_BYTES`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#tool_response_too_large"
    },
    {
      "code": "TOOL_UNREACHABLE",
      "http_status": 502,
      "description": "An http-type tool call never got a response: the target's host did not resolve, refused or dropped the connection, or timed out. The message names the network failure and the error `meta` carries the URL and method. Distinct from `TOOL_HTTP_ERROR`, which is the target answering with a non-2xx status.",
      "resolution": "Check the tool's URL and that its host is reachable from the server; the message names the network failure. A timeout or a dropped connection may succeed on retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#tool_unreachable"
    },
    {
      "code": "TRIGGER_ACTION_NOT_ALLOWED",
      "http_status": 400,
      "description": "A trigger field is incompatible with its type: `action` is only valid for tool targets (and required for soat/mcp tools), and `cron` is required for schedule triggers and rejected otherwise.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#trigger_action_not_allowed"
    },
    {
      "code": "TRIGGER_CAUSATION_LIMIT",
      "http_status": 409,
      "description": "An event trigger refused to extend the causal chain that reached it — it is already in the chain, or the chain has run too deep.",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#trigger_causation_limit"
    },
    {
      "code": "TRIGGER_CREATOR_UNAVAILABLE",
      "http_status": 409,
      "description": "The trigger creator no longer exists, so the firing identity cannot be resolved.",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#trigger_creator_unavailable"
    },
    {
      "code": "TRIGGER_FIRING_ABANDONED",
      "http_status": 500,
      "description": "An event firing was interrupted without reaching a result, repeatedly, and is not attempted again. `meta.attempts` is how many starts it had. It appears as a firing's recorded `error`, never as a response: by the time it is written there is nobody left to answer.",
      "resolution": "The dispatch did not survive long enough to record an outcome. Check the target named by the trigger for work that ends the process, then re-fire the trigger manually.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#trigger_firing_abandoned"
    },
    {
      "code": "TRIGGER_INPUT_INVALID",
      "http_status": 400,
      "description": "The effective input is invalid for the target (empty agent input, or an orchestration input_schema violation).",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#trigger_input_invalid"
    },
    {
      "code": "TRIGGER_NOT_ACTIVE",
      "http_status": 409,
      "description": "The trigger is inactive and cannot fire.",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#trigger_not_active"
    },
    {
      "code": "TRIGGER_RECURSION_FORBIDDEN",
      "http_status": 403,
      "description": "A trigger-scoped credential cannot fire a trigger, preventing unbounded trigger→trigger loops.",
      "resolution": "The credential is authenticated but lacks this action, or is scoped to another project. Grant the action in an IAM policy, or use a credential that has it.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#trigger_recursion_forbidden"
    },
    {
      "code": "TRIGGER_TARGET_NOT_FOUND",
      "http_status": 400,
      "description": "The trigger target does not exist in the project, or its type does not match target_type.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#trigger_target_not_found"
    },
    {
      "code": "TRIGGER_TYPE_IMMUTABLE",
      "http_status": 400,
      "description": "A trigger’s type cannot be changed after creation.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#trigger_type_immutable"
    },
    {
      "code": "UNAUTHORIZED",
      "http_status": 401,
      "description": "Authentication is required or the token is invalid.",
      "resolution": "Send `Authorization: Bearer <token>` — a user token from `POST /api/v1/users/login`, a project API key (`sk_…`), or an OAuth access token. Discovery metadata for the OAuth flow is at `/.well-known/oauth-authorization-server`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#unauthorized"
    },
    {
      "code": "UNSUPPORTED_FILE_TYPE",
      "http_status": 400,
      "description": "The referenced file has a content type that cannot be ingested. Supported types: application/pdf, text/plain, text/markdown.",
      "resolution": "The file's media type has no parser on this deployment. Convert it to a supported type, or add an ingestion rule that does.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#unsupported_file_type"
    },
    {
      "code": "UPLOAD_TOKEN_EXPIRED",
      "http_status": 410,
      "description": "The upload token has expired. Request a new one.",
      "resolution": "Request a fresh upload token; tokens are single-use and short-lived by design.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#upload_token_expired"
    },
    {
      "code": "UPLOAD_TOKEN_NOT_FOUND",
      "http_status": 404,
      "description": "The upload token does not exist.",
      "resolution": "Check the id and the project the credential can see, then retry. Listing the collection confirms whether the resource exists.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#upload_token_not_found"
    },
    {
      "code": "UPLOAD_TOKEN_USED",
      "http_status": 409,
      "description": "The upload token has already been used.",
      "resolution": "This upload token has already been redeemed. Request a new one for another upload.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#upload_token_used"
    },
    {
      "code": "UPLOAD_TOO_LARGE",
      "http_status": 413,
      "description": "The multipart upload exceeds the byte ceiling this deployment accepts (`FILE_UPLOAD_MAX_BYTES`, 25 MB by default). The request is refused while the body is still streaming, so nothing was stored. Send a smaller file, or ask the operator to raise the ceiling.",
      "resolution": "The upload is over this deployment's byte ceiling. Send a smaller file, or ask the operator to raise `FILE_UPLOAD_MAX_BYTES`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#upload_too_large"
    },
    {
      "code": "VALIDATION_FAILED",
      "http_status": 400,
      "description": "The request body or query string failed validation.",
      "resolution": "Fix the request and retry. Unknown fields are rejected outright, so compare the payload against the operation in `/openapi.json`; `meta` names the offending field when the check can identify one, and for an unknown query parameter lists `unknown_query_parameters` and `accepted_query_parameters`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#validation_failed"
    },
    {
      "code": "VERSION_CONFLICT",
      "http_status": 409,
      "description": "The write named a version other than the one the resource currently holds, or a concurrent write took that version first. `meta.current_version` is the version in force, and `meta.expected_version` the one the request named. Nothing was written: re-read the resource, rebase the change on what it now holds, and retry against the version `meta.current_version` names.",
      "resolution": "Re-read the resource, re-apply the change on top of the version `meta.current_version` names, and retry with that version. A retry of the same body against the same stale version conflicts again.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#version_conflict"
    },
    {
      "code": "WORKFLOW_HAS_OPEN_TASKS",
      "http_status": 409,
      "description": "The workflow has one or more open tasks and cannot be deleted.",
      "resolution": "The request is well-formed but the resource is not in a state that allows it. Resolve the conflicting state named in the message, then retry.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#workflow_has_open_tasks"
    },
    {
      "code": "WORKFLOW_MIGRATION_NOT_FOUND",
      "http_status": 404,
      "description": "The workflow migration does not exist, or belongs to another workflow.",
      "resolution": "Check the id and the project the credential can see, then retry. Listing the collection confirms whether the resource exists.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#workflow_migration_not_found"
    },
    {
      "code": "WORKFLOW_NOT_FOUND",
      "http_status": 404,
      "description": "The workflow does not exist or is not accessible.",
      "resolution": "Check the id and the project the credential can see, then retry. Listing the collection confirms whether the resource exists.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#workflow_not_found"
    },
    {
      "code": "WORKFLOW_VALIDATION_FAILED",
      "http_status": 400,
      "description": "The workflow definition is invalid (e.g. duplicate state names, not exactly one initial state, a transition referencing an unknown state, a malformed guard, or an on_enter dispatch missing its target).",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#workflow_validation_failed"
    },
    {
      "code": "WORKFLOW_VERSION_NOT_FOUND",
      "http_status": 400,
      "description": "The workflow has no version with that number. `meta.version` names it; list the workflow versions to see which exist.",
      "resolution": "Fix the request and retry — the payload, parameters, or referenced ids are invalid. Compare the request against the operation in `/openapi.json`.",
      "docs_url": "https://soat.ttoss.dev/docs/error-codes#workflow_version_not_found"
    }
  ]
}
