---
summary: "ErrorContract.recovery is now required (≥ 5 words, lint-validated). Decoupled from runtime data.recovery.hint — no auto-population, just a forcing function for thoughtful authoring."
breaking: true
---

# 0.8.4 — 2026-04-29

`recovery: string` joins `code`, `reason`, and `when` as a required field on every `ErrorContract` entry. Closes [#85](https://github.com/cyanheads/mcp-ts-core/issues/85).

The contract `recovery` and the throw-site `data.recovery.hint` are **decoupled by design**. The contract field is descriptive metadata read by the linter and scaffolding skills (a forcing function for thoughtful authoring). The wire payload's `data.recovery.hint` — which 0.8.3's error-path parity invariant mirrors into `content[]` text — is populated separately at the throw site by the author when dynamic context matters. No magic, no hidden transformation.

## Changed

- **`ErrorContract.recovery: string`** (`src/types-global/errors.ts`) — required at the TypeScript type level. Existing tools that declare `errors[]` won't compile without a `recovery` string per entry.

## Added

- **Three lint rules** (`src/linter/rules/error-contract-rules.ts`):
  - `error-contract-recovery-required` — error when `recovery` is missing or non-string
  - `error-contract-recovery-empty` — error when `recovery` is empty or whitespace-only
  - `error-contract-recovery-min-words` — warning when `recovery` has fewer than 5 words (forcing function against placeholders like "Try again.")

## Docs

- `CLAUDE.md` / `AGENTS.md` (root + `templates/`) — Error Handling sections updated with the required `recovery` field and the decoupling principle for `data.recovery.hint`.
- `skills/add-tool/SKILL.md` v2.1 → v2.2 — template scaffolds `recovery` in `errors[]`.
- `skills/api-errors/SKILL.md` v1.1 → v1.2 — documents the field, lint rules, and decoupling principle.
- `skills/design-mcp-server/SKILL.md` v2.7 → v2.8 — recovery-hint shape corrected to canonical nested `recovery: { hint: ... }`. Closes [#82](https://github.com/cyanheads/mcp-ts-core/issues/82).
- `templates/src/mcp-server/tools/definitions/echo.tool.ts` — `empty_message` entry gains a `recovery` string.

## Migration

Every existing `errors[]` entry needs a `recovery` string. TypeScript will flag missing entries on upgrade — fix in place.

```ts
// Before
errors: [
  { reason: 'no_match', code: JsonRpcErrorCode.NotFound,
    when: 'No item matched.' },
],

// After
errors: [
  { reason: 'no_match', code: JsonRpcErrorCode.NotFound,
    when: 'No item matched.',
    recovery: 'Broaden the query or check the spelling and try again.' },
],
```

The `recovery` string is contract metadata, not the wire-payload hint. To surface dynamic recovery guidance at the call site (mirrored into `content[]` text by 0.8.3's parity invariant), pass it explicitly:

```ts
throw ctx.fail('no_match', `No item ${id}`, {
  recovery: { hint: `No item ${id}; try a different ID.` },
});
```

## Maintenance

- Dependencies refreshed via `bun update --latest`. All minor/patch — `@opentelemetry/*` (0.215.0 → 0.216.0, 2.7.0 → 2.7.1), `@cloudflare/workers-types` (4.20260426.1 → 4.20260429.1), `unpdf` (1.6.1 → 1.6.2), and others.
