Skip to content

fix(itx): getItxErrorCode must not consult error.name — capnweb drops it in transit#1462

Merged
jonastemplestein merged 2 commits into
mainfrom
itx-error-code-duck-typing
Jun 10, 2026
Merged

fix(itx): getItxErrorCode must not consult error.name — capnweb drops it in transit#1462
jonastemplestein merged 2 commits into
mainfrom
itx-error-code-duck-typing

Conversation

@jonastemplestein

@jonastemplestein jonastemplestein commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Narrowed after #1447 landed: that PR fixed the e2e test's assertions (asserting the real wire shape, name === "Error" + raw code), which unblocks preview e2e on main. What it did NOT fix is the detection helper itself — getItxErrorCode still requires error.name === "ItxError", and capnweb 0.8.0 drops custom error names in transit (the receiver maps only builtin names to classes; the props loop skips name on both ends). So after any capnweb hop, every runtime consumer of the helper — react hooks, stream-tail, isItxAccessError retry predicates — fails to recognize kernel errors and treats NOT_FOUND/FORBIDDEN like connection noise.

Probed against a live preview deployment:

name: Error                    ← dropped by capnweb
code: NOT_FOUND                ← survives (own enumerable prop)
details: {"projectIdOrSlug":"definitely-not-a-project"}  ← survives

Fix

getItxErrorCode duck-types on the closed five-code set alone; name is not consulted (it cannot be, after capnweb). Set membership keeps foreign coded errors (ECONNREFUSED, …) out. The unit-test simulateCapnwebCrossing helper no longer reattaches name by hand — that hand-modeled reattachment is exactly how the original bug stayed green in unit tests while failing on the real wire. Docs in errors.ts updated to match (merged with #1447's wording).

Verification

  • The capnweb-crossed shape (plain Error + code) is now detected; unit tests assert it
  • pnpm test:itx-stream-subscribe (real Workers RPC boundary, which legitimately preserves name) still passes
  • Full apps/os suite, typecheck, lint clean; e2e verified earlier against a live preview deployment (preview_6)

🤖 Generated with Claude Code


Note

Medium Risk
Changes shared error-classification used for retry vs access-failure handling across capnweb clients; behavior widens slightly (code-only shapes now match) but is constrained by the five-code allowlist.

Overview
getItxErrorCode no longer requires error.name === "ItxError" — it treats any object whose code is one of the five itx codes as an ItxError. That matches errors after a capnweb RPC crossing, where the receiver rebuilds a plain Error and drops the name while code / details still arrive as own props.

Docs on getItxErrorCode in errors.ts now spell out why name must not be used and how the closed code set avoids colliding with other code-bearing errors (e.g. ECONNREFUSED).

Unit tests were aligned with real capnweb: simulateCapnwebCrossing no longer re-attaches name, duck-typed cases use plain Error + code only, and rejection cases use foreign codes instead of wrong name.

Reviewed by Cursor Bugbot for commit 5c3e6d3. Bugbot is set up for automated code reviews on this repo. Configure here.

jonastemplestein and others added 2 commits June 10, 2026 16:33
…s in transit

Every preview e2e run on main has been red since #1456 merged: its own new
e2e test ("kernel errors cross capnweb as ItxError-shaped errors with
codes") failed on the PR's own preview run and on every full preview run
since, asserting error.name === "ItxError" while the wire delivers "Error".

capnweb 0.8.0's receiver maps only builtin error names to classes; an
unknown name like "ItxError" reconstructs as plain `Error`, and the props
loop skips `name` on both ends — so the name never crosses a capnweb
session (Workers RPC, by contrast, preserves it). The unit-test simulation
of the crossing reattached `name` by hand, encoding the wrong model, which
is why unit tests stayed green while the real wire failed.

Detection now rides on the closed five-code set alone: getItxErrorCode
accepts any object whose `code` is one of the five, name not consulted.
The five-code set membership is what keeps Node's ECONNREFUSED-style coded
errors out. The e2e test now asserts the real wire shape (plain Error +
code + details, detected via getItxErrorCode), and the simulation helper
matches what capnweb actually does.

Verified against a live preview deployment (preview_6): the previously
failing test passes; the Workers-RPC boundary suite (which legitimately
keeps `name`) still passes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…yping

# Conflicts:
#	apps/os/src/itx/e2e/itx.e2e.test.ts
#	apps/os/src/itx/errors.ts
@jonastemplestein jonastemplestein changed the title fix(itx): duck-type ItxError on code alone — capnweb drops error names in transit fix(itx): getItxErrorCode must not consult error.name — capnweb drops it in transit Jun 10, 2026
@jonastemplestein jonastemplestein merged commit 3e34172 into main Jun 10, 2026
7 of 8 checks passed
@jonastemplestein jonastemplestein deleted the itx-error-code-duck-typing branch June 10, 2026 15:48
jonastemplestein added a commit that referenced this pull request Jun 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant