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

# MCP Write Envelopes and Error Codes — Substrate Docs

> The success envelope every Substrate write returns, plus all 8 error codes and how to handle version_mismatch and transition_blocked.

Every Substrate write tool returns the same envelope shape on success; every failure returns a structured error object. Read tools return raw data directly and are not covered here. Understanding both shapes up front means you will never need to guess what a response means.

***

## The Success Envelope

```json theme={null}
{
  "ok": true,
  "applied": {
    "entity": "task",
    "id": "9a5af742-86c0-4ae0-ae69-3c732330702c",
    "version": 4,
    "state": { "…": "the entity as written" }
  },
  "policies_fired": [
    {
      "policy_id": "resp-tests",
      "policy_name": "Tests during development",
      "policy_type": "agent_responsibility",
      "description": "…",
      "message": "Write tests during development, not after."
    }
  ]
}
```

<ResponseField name="applied.entity" type="string">
  The type of entity that was written. One of `task`, `comment`, `board`, `group`, `policy`, or `project`.
</ResponseField>

<ResponseField name="applied.version" type="number | null">
  The post-write version of the entity. **Keep this value** — it is what you pass as `version` on your next update. Returns `null` for entities without optimistic concurrency (comments in practice).
</ResponseField>

<ResponseField name="policies_fired" type="array">
  Every policy that engaged on this write. An `agent_responsibility` entry carries a `message` authored by whoever configured the board, aimed at exactly this moment.
</ResponseField>

**Two things to do with every envelope:** keep the `applied.version`, and read `policies_fired`. If a message is present, it was written by the board author to guide the agent at this precise point in the workflow.

***

## The Error Object

```json theme={null}
{
  "ok": false,
  "error": {
    "code": "transition_blocked",
    "message": "Cannot move to 'review': tests_passing is not set.",
    "details": { "…": "structured context" }
  }
}
```

| Code                 | HTTP | Meaning                                                                                           | What to do                                                                                                                |
| -------------------- | ---- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `transition_blocked` | 422  | A `transition_guard` rejected the move.                                                           | Read the message, satisfy the requirement, retry. If the blocking field is `human_only`, stop and report it to the human. |
| `version_mismatch`   | 409  | Your version is stale.                                                                            | Re-read the entity, reconcile your intended change, retry with the fresh version. Never blindly overwrite.                |
| `schema_violation`   | 400  | Input does not match the schema — bad field type, malformed policy definition, or unknown key.    | The message names the offending path. Fix it and retry.                                                                   |
| `not_found`          | 404  | No entity with that id, or no `.substrate/` directory in the working directory.                   | Re-resolve ids from a read call; verify the working directory.                                                            |
| `conflict`           | 409  | The write contradicts current state — for example, archiving a group that still has active tasks. | Clear the conflict first, then retry.                                                                                     |
| `forbidden`          | 403  | The write is refused by design — most commonly an agent attempting to set a `human_only` field.   | Do not retry. Report the situation to the human.                                                                          |
| `substrate_corrupt`  | 500  | An on-disk board file is malformed or structurally invalid.                                       | This is user-fixable config, not a Substrate bug. The message names the file. Run `substrate validate`.                   |
| `internal_error`     | 500  | A Substrate bug.                                                                                  | Run `substrate diagnose` and `substrate logs --errors`, then file a bug.                                                  |

***

## Handling `version_mismatch`

Optimistic concurrency exists because several agents may work on the same board at once. When a mismatch occurs, Substrate hands you the current version:

```json theme={null}
{
  "ok": false,
  "error": {
    "code": "version_mismatch",
    "message": "…",
    "details": { "current_version": 7 }
  }
}
```

Re-read the entity, reconcile your intended change against what actually changed since your last read, and retry with the fresh version. Do **not** simply resend your original payload with `current_version` substituted — that overwrites whatever the other writer did.

<Note>
  In v0.7.0 a `version_mismatch` tells you the version moved, but not what changed or who changed it. Call `get_task_history` to find out.
</Note>

***

## Handling `transition_blocked`

The error names the guard and the unmet condition. The right response depends on who can clear the block:

**Agent-settable field** — Do the required work, set the field via `update_task`, then retry the move.

**`human_only` field** — You have no path to set it. Call `list_pending_approvals` and report the exact approval command to the human:

```sh theme={null}
substrate approve <task_id> <field>
```

Each block is also recorded as a `move_blocked` event in the task's history, so `get_task_history` shows not just what a task did, but what it was prevented from doing and why.
