> ## Documentation Index
> Fetch the complete documentation index at: https://docs.semicola.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors

> Handle validation, account, revision, upstream and partial-result failures from v3 tools.

A v3 tool can fail while the MCP transport succeeds. Always inspect the tool result: a failure has
`isError: true` and a structured body. Read `structuredContent.code` and the fields beside it, never
the rendered text.

## The error shape

```json theme={null}
{
  "isError": true,
  "structuredContent": {
    "code": "REVISION_CONFLICT",
    "message": "Campaign cmp_01JB… changed since revision 4.",
    "recovery": "fix_input",
    "field": "expectedRevision",
    "suggestion": "Read the campaign again and retry with its current revision."
  }
}
```

| Field        | Meaning                                                                         |
| ------------ | ------------------------------------------------------------------------------- |
| `code`       | Stable, machine-readable reason. Branch on this.                                |
| `message`    | A sentence for people. It can change; do not parse it.                          |
| `recovery`   | What to do next: `retry`, `fix_input`, `ask_user`, `contact_support` or `none`. |
| `field`      | The input field at fault, when there is one.                                    |
| `suggestion` | A concrete next step, when the server has one.                                  |

## Two results that are not errors

<ResponseField name="needs_input" type="result">
  `{ "status": "needs_input", "question": "…", "missingFields": ["budget.currency"] }`. A required
  fact is missing. Ask the person the question, then call again with the answer. Never invent a
  value to get past it.
</ResponseField>

<ResponseField name="pending_confirmation" type="result">
  `{ "status": "pending_confirmation", "confirmationUid": "cnf_…", "summary": "…", "expiresAt": "…",
      "writeExecuted": false }`. The write is paused for a person's approval. Show the summary; after
  they approve, call the same tool again with `confirm: true` and the `confirmationUid` (for a
  campaign launch, `confirmLaunch: true`). Confirmations expire after 15 minutes.
</ResponseField>

## Common codes

| Code                                    | What happened                                                                                                                                           | What to do                                                                                             |
| --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| `VALIDATION_ERROR`, `BAD_REQUEST`       | The input did not match the schema.                                                                                                                     | Fix `field` and call again. Check the [Tool Catalog](/v3/tool-catalog).                                |
| `CURRENCY_MISMATCH`                     | The budget currency differs from the advertiser's.                                                                                                      | Use the advertiser's primary currency.                                                                 |
| `UNAUTHORIZED`                          | No valid credential.                                                                                                                                    | Re-run OAuth or check the API key.                                                                     |
| `FORBIDDEN`, `ACCESS_DENIED`            | The account or role cannot do this.                                                                                                                     | Call `get_status`; switch accounts or ask an admin.                                                    |
| `TOS_ACCEPTANCE_REQUIRED`               | The organization has not accepted the current terms.                                                                                                    | Ask an admin to accept them in Plan & billing.                                                         |
| `NOT_FOUND`                             | No such object in the active account.                                                                                                                   | Check the id and the active account.                                                                   |
| `REVISION_CONFLICT`                     | Someone changed the object since you read it.                                                                                                           | Read it again and retry with the new `expectedRevision`.                                               |
| `CONFLICT`                              | The same idempotency key was used with a different body, or the object is in the wrong state.                                                           | Use a new key for a new attempt; re-read state.                                                        |
| `BUYER_SETUP_REQUIRED`                  | Buyer setup is incomplete for this seller or advertiser.                                                                                                | Follow the next action from `get_status`.                                                              |
| `INSUFFICIENT_MEDIA_BUDGET`             | Allocations exceed the campaign budget.                                                                                                                 | Lower allocations or raise the budget.                                                                 |
| `CAPABILITY_NOT_SUPPORTED`              | The seller or account cannot do this.                                                                                                                   | Choose another seller or approach.                                                                     |
| `RATE_LIMITED`                          | Too many requests.                                                                                                                                      | Wait for `Retry-After`, then retry.                                                                    |
| `WRONG_ACCOUNT`                         | The tool belongs to the other account kind (a buyer tool with a Seller account selected, or the reverse).                                               | Call `switch_account` with `details.switchAccount.arguments`, then retry.                              |
| `SPEND_DENOMINATION_UNRESOLVED` (422)   | Delivery for a media buy in scope is reported in more than one currency, so no spend figure would be correct. `details.mediaBuyIds`, `unresolvedCount`. | Don't retry: it reproduces. Report the ids to support, and scope the report to exclude them meanwhile. |
| `VERSION_UNSUPPORTED` (422)             | AdCP: a different major version, or `sync_accounts` with AdCP 3.2 account-identity fields a 3.0/3.1 storefront can't hold.                              | See [AdCP versions](/concepts/adcp#versions).                                                          |
| `SERVICE_UNAVAILABLE`, `INTERNAL_ERROR` | A temporary platform problem, or a tool call that reached the 30-minute limit.                                                                          | Read state first, then retry with the same idempotency key and backoff.                                |

<Note>
  `NOT_FOUND` deliberately hides whether an object exists in some other account. Do not read it as
  evidence about accounts you cannot see.
</Note>

## Partial results

Some tools talk to many sellers at once, so success is not all-or-nothing.

* **Proposal requests** report each seller separately: `quoted`, `products` or `failed`, with a
  summary such as "Asked 9 sellers · 6 responded · 2 pending · 1 failed". Keep the good answers; one
  failed seller does not spoil the execution.
* **Campaign launch** returns `mediaBuysExecuted` and one entry in `errors` per failed media buy, each
  with `recovery` (`transient`, `correctable` or `terminal`) and `retrySafe`. Launching again
  resubmits only the failed draft buys.

## Retrying safely

1. If a call timed out or the connection dropped, **read first**: the write may have happened.
2. Retry a write with the **same** `idempotencyKey` only if it is the same logical attempt. Change
   the key when you change the request.
3. After a `REVISION_CONFLICT`, re-read, re-decide, then write with the new revision. Do not blindly
   bump the number.
