# Refusals

Every code a refused call can carry, when it happens and the way out, from the connector's own checks to the errors Entz itself returns.

When the connector cannot do what the agent asked, the call comes back as an error rather than a result. You see it in your client among the agent's tool calls; the people in the document see nothing. The error holds the refusal as JSON, with its `code`, the index of the failing op in `op` when there is one, a `message` and `data`, followed by a line naming the guide entry that explains the way out:

```text
{"code":"guard_mismatch","op":0,"message":"the block changed since it was read; their words win","data":{"h":"7be41d09","xml":"<paragraph id='2kx9q1.16' h='7be41d09'>Q3 ships the connector to every paid workspace.</paragraph>"}}
Nothing landed. guide(items=["refusal.guard_mismatch"]) says how to recover.
```

The connector's instructions tell the agent to read that entry with the `guide` tool, which says how to recover. Most refusals mean a person got there first, and the way forward is the same each time: read what stands, keep their words, and work with them.

## The connector's refusals

These come from the connector's own checks, before anything reaches Entz. A call refused this way changes nothing at all.

| Code | When | The way out |
|---|---|---|
| `guard_mismatch` | Someone changed the block after the agent read it: `data.h` is its fingerprint now and `data.xml` the block as it stands. Also a write-level `ifRev` that is no longer the tab's revision, and a cell by position whose table's rows or columns, or whose words, changed since. | Keep their words: redo the edit against `data.xml` with `ifHash` set to `data.h`, or quote only the words to change. A cell whose table changed shape: read the table and count again. Never resend with `force`. |
| `missing_guard` | A whole-block replace or delete, or a whole cell's replace, came without a guard. | Add `ifHash` for one block or `ifRev` for the revision of the last read or answer. `force` only when you asked the agent to overwrite whatever is there. |
| `find_none` | The quoted words are not in the document as written, or `nth` is past the last match (`data.count`). | Quote the words as a read shows them: no Markdown, and never across two blocks. A `search` for a few of them shows what stands. If they are truly gone, the agent is told to say so rather than edit somewhere else. |
| `find_ambiguous` | The quoted words occur more than once (`data.count`). | Add `nth`, `within` or `parentId`, or quote more words. |
| `block_gone` | The block was removed, by the agent's own earlier replace or by a person. | After its own replace, the agent uses the ids from that answer. A block a person removed stays removed: the agent is told not to create it again. |
| `unknown_id` | No block, tab or comment has that id, or a reference is not a document id or link. | Use the full id, expanding a read's `.N` with the last full prefix above it. The `tabs` and `comments` lists give tab and comment ids. |
| `anchors_affected` | The op would remove every word an open comment thread hangs on (`data.threads`). | Narrow the edit so some of those words stay, or ask in the thread whether the passage should go. Only when a person asked for it: add `"allowDetach": true` to the op, which leaves the thread detached (the agent is told to say so), or resolve the thread first. |
| `last_block` | The op would delete a tab's last block. | Replace that block instead. |
| `last_tab` | The main tab was to be removed, but it is the document itself. | To start over, replace its blocks. The document goes only when its owner deletes it in Entz. |
| `too_many` | More than 64 ops in one call. | Split the write, a section per call. |
| `cell_none` | A cell position past the table's edge. `data` holds its `rows`, its `cols` and the header row's words, `columns`. | Count again, or read the table with `view`. |
| `shape_mismatch` | The op does not fit the blocks: `as: "text"` on a block without text or on a cell of several blocks, blocks replaced together from different lists, blocks inside cells moved, a table put inside a cell, a cell target that names something other than a table, or a cell's or a row's id used as a block (then `data.target` names the cell by position). | Follow the message. |
| `bad_move` | A move's place is one of the blocks moved, a block inside a table, or a cell. | Pick another place. |
| `bad_request` | The call is malformed, and the message names what is wrong: a chip token without an entry in `blocks` or an entry without a token, a date not written `YYYY-MM-DD`, a dropdown without options, or an action missing what it needs. | Check the call against the guide's `index` topic. |
| `rev_expired` | The connector no longer holds that revision. It keeps the newest 256 for each tab, and starts again after a restart, or after closing a document left unused for 10 minutes. | Read the outline and continue from its revision. |
| `access` | The agent cannot open the document: it keeps to its members and the agent's identity is not one, or the id is wrong, or the document was deleted. | The document's owner opens **Access…** and turns on **Anyone with the link**, with **Edit** for the agent to write. People can also be added by email there, but the agent's identity has no email. |
| `internal` | The document refused the change for a reason of its own, which the message gives, or the connector failed in a way it cannot name. | Read the outline and try once more. If it happens again, the agent is told to tell you. |

## Errors from Entz

Some calls are refused by Entz itself rather than by the connector: a comment, a tab change, or an edit on its way to the server. These keep Entz's own code, which has no guide entry; when the agent asks the guide for one, the guide answers with the list of entries it has.

| Code | When | What to do |
|---|---|---|
| `not-member` | The agent's identity may not do this in the document: the link let it in to view, so it may not comment or edit; or to comment, so it may not edit; or it was removed. Adding, renaming, moving and removing tabs need **Edit** too. | Under **Access…**, give the link the permission the agent needs (**Edit** to write, **Comment** to comment), then restart the connector. Members keep the permission they joined with, and a fresh start joins again with the new one. |
| `rate-limited` | A comment came too soon after other changes, and Entz asks the writer to wait. | Wait a moment and send it again. Edits held back this way never show this code: the connector sends them again by itself. |
| `too-large` | One write carried more than Entz takes at once (1 MiB). | Restart the connector, then write the content in smaller parts. |
| `quota` | The identity has created as many documents as Entz allows one identity. | Restart the connector, which gives it a fresh identity. |
| `rejected` | Entz refused the call for another reason, which the message names: a comment over 4,096 bytes, a thread that already has 100 comments, a tab name over 200 characters. A first connection that failed says `connect failed` here too. | Follow the message. For a failed connection, check your network and try again: the next call tries a new connection. |
| `disconnected`, `timeout` | The connection to Entz dropped, or a call or the first connection took too long. | Try again. The connector reconnects by itself, and edits made meanwhile go up once it is back. |

An edit that Entz refuses (`not-member`, `too-large`) differs from the connector's own refusals in one way: it has already been applied to the connector's copy of the document, although nobody else ever sees it. The agent's later reads in the same session still show it, and later edits to that document are refused the same way. Restarting the connector starts again from what Entz holds; [Troubleshooting](/docs/mcp/troubleshooting/#access-is-refused) walks through it.
