---
summary: "Canvas not-found errors carry reason 'canvas_not_found' plus a recovery hint so consumer error contracts populate on the wire, classifyDuckdbError passes structured McpErrors through unchanged (register_as_clash / export_path_* keep code and reason), and the enrichment trailer gains a leading blank-line separator."
breaking: false
security: false
agent-notes: |
  Consumer-declared `canvas_not_found` error contracts now populate
  `data.reason` and `data.recovery.hint` on the wire — the structured shape
  originates at the framework throw sites (`CanvasRegistry`,
  `DuckdbProvider.requireCanvas`), which run before handler code. The default
  hint no longer suggests omitting `canvas_id`; it now points to re-running
  the producing tool or re-checking the id.
---

# 0.10.12 — 2026-07-05

## Changed

- **`api-canvas` skill 1.8** — documents the structured `canvas_not_found` shape: the token-sharing "Unknown id" row and the `instance.query` section now state `data.reason: 'canvas_not_found'` with the revised recovery guidance.

## Fixed

- **Enrichment trailer separator** — `renderEnrichmentTrailer()` leads the trailer's `content[]` text block with a blank-line separator, so clients that concatenate adjacent text blocks with no join (Claude Desktop, claude.ai) no longer glue it onto the last domain line; markdown collapses consecutive blank lines, so clients that insert their own separator render at most one blank line either way ([#257](https://github.com/cyanheads/mcp-ts-core/issues/257)).
- **`canvas_not_found` reason/recovery** — `CanvasRegistry`'s not-found throws (`acquire()`, `touchOrThrow()`, `touchWithTable()`, `touchWithSqlTables()`) and `DuckdbProvider.requireCanvas()` carry `data.reason: 'canvas_not_found'`, the offending `canvasId`, and a default `data.recovery.hint`; consumer tools declaring a `canvas_not_found` error contract were dead-letter before — the throw happens inside the framework, before handler code runs. The default guidance drops "Omit canvas_id to start a new canvas" (omission mints a fresh, empty canvas, and a tool that requires the parameter rejects the retry, looping the agent) in favor of re-running the producing tool or re-checking the id ([#261](https://github.com/cyanheads/mcp-ts-core/issues/261)).
- **`classifyDuckdbError()` McpError pass-through** — an already-structured `McpError` returns unchanged instead of being reclassified to `DatabaseError`, preserving the `ValidationError` code and `data` (`register_as_clash` + `tableName` from `ensureTableMissing()`, `export_path_absolute`/`export_path_escapes` from `resolveExportPath()`) across all four provider catch sites ([#254](https://github.com/cyanheads/mcp-ts-core/issues/254)).
