---
title: "MCP errors and recovery"
description: "Every structured error the ComStack MCP server returns — what triggers it and the exact step to recover — for agents that self-correct."
url: "https://comstack.ai/docs/mcp/errors/"
---
## What this is

A reference of the structured errors the ComStack MCP server returns, with the trigger and the exact recovery step for each. It exists so an agent can self-correct without a human: every write tool fails loud with an actionable message rather than degrading silently.

## How it works

Errors arrive as MCP errors with a code (`InvalidRequest`, `InvalidParams`) and a message; several also carry a structured `data` payload (for example `duplicate_draft_target` includes a `collisions` array). Validation is single-pass — `create-page` and `update-page` return *every* problem at once, each with a `fix` string. Read the whole list before retrying.

## Errors and recovery

### Validation

**`ValidationFailed` (InvalidParams)** — page metadata or content failed the template's rules. The message is `ValidationFailed: page does not match all requirements (N issue(s))` followed by one line per issue (`field`, `problem`, `supported_values`, `valid_examples`, `expected_range`, `fix`). *Fix:* apply every `fix`; consult `get-doc-template id='…'` for the schema and `metadata_example`. Frequent offenders: `title` 10–60 chars, `description` 50–160, `keywords` an array (a JSON-encoded string is coerced and the `fix` shows the correct array), and content that starts with `#` instead of `##`.

### Page identity and collisions

**`A page already exists at path '…'` (path_exists)** — the `path` is taken. *Fix:* `update-page` with that `path`, or choose a new `path`.

**`Slug '…' (language '…') is already used …` (slug_in_use)** — another page already deploys to that URL. *Fix:* `update-page` the conflicting page, or pick a different slug. The same slug in a *different* language is allowed.

**`Invalid id format`** — the `path` contained a slash. *Fix:* `path` is a flat doc id; put slashes in `metadata.slug` (slug `docs/mcp` → path `docs-mcp`).

**`Page not found: '…'`** — `get-page-content` / `update-page` got a `path` or `(slug, language)` that resolves to nothing. *Fix:* re-resolve against `get-project-state`; remember the `path` rotates after a publish.

### Wrong editor

**`… is a CUSTOM page (metadata.type="custom")`** — `update-page` hit a custom page. The full message: `Edit it with upload-custom-page (body_source + <T key=…> markers), not update-page. update-page edits knowledge (markdown) pages only.` *Fix:* edit it with `upload-custom-page`.

**`wrong_tool_knowledge_page`** — `upload-custom-page` hit a knowledge page: `'…' (slug '…') is a KNOWLEDGE (markdown) page, not a custom page. upload-custom-page would overwrite its body with opaque body_source.` *Fix:* edit it with `update-page`, or pick a different slug for the custom page.

### Publishing

**`duplicate_draft_target` (InvalidRequest)** — two pending drafts target the same `(slug, language)`; **no token is minted**. The `data.collisions[]` lists each colliding draft `path`. *Fix:* `discard-draft` the extras (or change a slug), then `publish` again.

**`Invalid or already-used confirmation token`** — the token expired (5-min TTL) or was already used. *Fix:* call `publish` again for a fresh token.

**Manifest changed since the dry run** — `publish-confirm` detected a draft or theme change since `publish`. *Fix:* re-run `publish` and review the new manifest.

### Auth, roles, and safeguards

**`project_name does not match project …`** — the `project_name` echo did not match (the comparison is case-insensitive and trimmed). *Fix:* read the exact name from `get-project-state`.

**`Insufficient permission: this tool requires 'manager' …`** — your role is below the tool's minimum (publishing and destructive tools need `manager`). *Fix:* a manager performs it, or the role is elevated.

**`This API key is scoped to project '…'`** — a service key was used with a different `project_id` than it is bound to. *Fix:* pass the matching `project_id`, or use a key for that project.

**`invalid_token` / `invalid_api_key` (401)** — the bearer token or API key is missing, expired, or wrong. *Fix:* re-authorize (OAuth) or rotate the key.

### Custom-page specific

**`is_faq=true is forbidden on custom-page docs (template.forbids_is_faq=true)`** — FAQ JSON-LD is a knowledge-page concern. *Fix:* drop `is_faq`, or author the FAQ as a knowledge page.

**`body_source is … above the 2 MB hard cap`** — the uploaded source is too large. *Fix:* move large inline assets out of `body_source`.

**`Marker extraction failed …`** — a `<T key>` / `data-t-key` marker did not parse. *Fix:* correct the marker at the reported offset and re-upload. Marker keys must match `/^[a-z][a-z0-9_.]*[a-z0-9]$/` (minimum two characters).

**`blocked href scheme` (blocked_href_scheme)** — `body_source` contains a `javascript:`, `data:` or `vbscript:` URL in an `href`/`xlink:href` attribute. These ship to the browser as authored, so the upload rejects them outright (obfuscated/entity-encoded forms included). *Fix:* replace with `https:`, `mailto:`, `tel:`, relative or `#anchor` URLs. `data:` URLs in `src` attributes (inline images) are unaffected.

## When to use it

- Building an agent that must recover from a failed tool call on its own
- Looking up the precise recovery for a message you just hit
- Pre-flighting automation against the validation rules

## Related

- [Publishing](/docs/mcp/publishing.md) — `duplicate_draft_target` and the token flow in context
- [Page types](/docs/mcp/page-types.md) — the wrong-tool guards explained
- [Custom pages](/docs/custom-pages.md) — authoring custom pages with `upload-custom-page`
- [MCP resources](/docs/mcp/resources.md) — error references available as `transformento://` resources
