Skip to content

Commit d0bbf34

Browse files
docs(core): qualify ResourceNotFoundError fromError reconstruction; fix cross-bundle example
- JSDoc / changeset / migration.md now state that ProtocolError.fromError reconstructs ResourceNotFoundError for either code only when error.data carries `uri`; a bare -32002 without data.uri stays a generic ProtocolError. - migration.md example: drop the outer `instanceof ProtocolError` gate (it defeats the cross-bundle case the prose describes); the example now feeds code+data straight into fromError and tests the locally-created result.
1 parent 926a44b commit d0bbf34

3 files changed

Lines changed: 23 additions & 15 deletions

File tree

.changeset/resource-not-found-32602.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,14 @@ emitted `-32602` on earlier revisions, so v1.x peers see no change.
1111

1212
This supersedes an interim `-32002` emission that shipped in earlier v2 alphas. The
1313
era-aware encode seam (`WireCodec.encodeErrorCode`) maps any handler-thrown `-32002`
14-
to `-32602` on the wire, so a handler written against the older alpha behaves
15-
identically without changes.
14+
to `-32602` on the wire; note that a `-32002` thrown without `data.uri` is emitted as
15+
a bare `-32602` and is no longer recognizable as resource-not-found — throw
16+
`ResourceNotFoundError` (or include `data: { uri }`) to preserve the classification.
1617

1718
`ProtocolErrorCode.ResourceNotFound` (`-32002`) remains importable as receive-tolerated
1819
vocabulary; clients should accept both `-32602` and `-32002` from peers (the
1920
specification's backwards-compatibility clause). The new typed `ResourceNotFoundError`
20-
class carries `data.uri`, and `ProtocolError.fromError` recognises both codes by the
21-
`data.uri` shape.
21+
class carries `data.uri`, and `ProtocolError.fromError` reconstructs it from a `-32602`
22+
only when `error.data` is exactly `{ uri: string }` (and nothing else), and from a
23+
legacy `-32002` whenever `data.uri` is a string; a bare `-32002` without `data.uri`
24+
stays a generic `ProtocolError`.

docs/migration.md

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1287,21 +1287,24 @@ with the `allowInputRequired: true` request option plus the `withInputRequired()
12871287
### Resource not found is `-32602` on every revision; typed `ResourceNotFoundError`
12881288

12891289
`resources/read` for an unknown URI now answers with JSON-RPC error code **`-32602` (Invalid Params)** on every protocol revision, with `error.data.uri` echoing the requested URI. The 2026-07-28 specification requires `-32602`; the v1.x SDK already emitted `-32602` on earlier
1290-
revisions, so v1.x peers see no change. An interim `-32002` emission that shipped in earlier v2 alphas is reverted: the era encode seam maps any handler-thrown `-32002` to `-32602` on the wire, so a handler written against the older alpha behaves identically without changes.
1290+
revisions, so v1.x peers see no change. An interim `-32002` emission that shipped in earlier v2 alphas is reverted: the era encode seam maps any handler-thrown `-32002` to `-32602` on the wire; note that a `-32002` thrown without `data.uri` is emitted as a bare `-32602` and is no longer recognizable as resource-not-found — throw `ResourceNotFoundError` (or include `data: { uri }`) to preserve the classification.
12911291

12921292
`ProtocolErrorCode.ResourceNotFound` (`-32002`) **remains importable** as receive-tolerated vocabulary: clients should accept both `-32602` and `-32002` from peers (the specification's backwards-compatibility clause). The new typed `ResourceNotFoundError` class carries the URI on
1293-
`.uri`, and `ProtocolError.fromError` recognizes both codes by the `data.uri` shape — recognize peers' errors by their code and `error.data`, not by `instanceof`, which does not survive bundling. Servers must not return an empty `contents` array for a non-existent resource (an
1294-
empty array is ambiguous between "exists but empty" and "does not exist").
1293+
`.uri`, and `ProtocolError.fromError` reconstructs it from a `-32602` only when `error.data` is exactly `{ uri: string }` (and nothing else), and from a legacy `-32002` whenever `data.uri` is a string (a bare `-32002` without `data.uri` stays a generic `ProtocolError`) — recognize peers' errors by their code and `error.data`, not by `instanceof`, which does not survive
1294+
bundling. Servers must not return an empty `contents` array for a non-existent resource (an empty array is ambiguous between "exists but empty" and "does not exist").
12951295

12961296
```typescript
12971297
import { ProtocolError, ResourceNotFoundError } from '@modelcontextprotocol/client';
12981298

12991299
try {
13001300
await client.readResource({ uri: 'file:///nope' });
13011301
} catch (error) {
1302-
const typed = error instanceof ProtocolError ? ProtocolError.fromError(error.code, error.message, error.data) : undefined;
1303-
if (typed instanceof ResourceNotFoundError) {
1304-
console.log('not found:', typed.uri);
1302+
// fromError reconstructs the typed class from code + data alone, so this
1303+
// works even when `error` crossed a bundle boundary and `instanceof` on
1304+
// the thrown object would not match.
1305+
const e = error as ProtocolError;
1306+
if (ProtocolError.fromError(e.code, e.message, e.data) instanceof ResourceNotFoundError) {
1307+
console.log('not found:', (e.data as { uri: string }).uri);
13051308
}
13061309
}
13071310
```

packages/core/src/types/errors.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,14 @@ export class ProtocolError extends Error {
8080
* SDK has always emitted on earlier revisions. The error data echoes the
8181
* requested URI.
8282
*
83-
* Recognise this error by checking `error.data.uri` is a string (a
84-
* `-32602` with `data.uri` is resource-not-found; any other `-32602` is an
85-
* ordinary Invalid Params). For backwards compatibility, clients should also
83+
* Recognise this error by checking `error.data` is exactly `{ uri: string }`
84+
* (a `-32602` whose data carries `uri` and nothing else is resource-not-found;
85+
* any other `-32602` is an ordinary Invalid Params). For backwards compatibility, clients should also
8686
* accept `-32002` as resource not found — earlier SDK builds emitted that
87-
* code, and {@linkcode ProtocolError.fromError} recognises both. Do not rely
88-
* on `instanceof` — it does not work across separately bundled copies of the
87+
* code, and {@linkcode ProtocolError.fromError} reconstructs this class for
88+
* either code **when `error.data` carries `uri`** (a bare `-32002` without
89+
* `data.uri` stays a generic {@linkcode ProtocolError}). Do not rely on
90+
* `instanceof` — it does not work across separately bundled copies of the
8991
* SDK.
9092
*/
9193
export class ResourceNotFoundError extends ProtocolError {

0 commit comments

Comments
 (0)