ItxError: five-code structured kernel errors over capnweb#1456
Merged
Conversation
New kernel module apps/os/src/itx/errors.ts: ItxError (Error + own
enumerable code/details, duck-typed detection via getItxErrorCode — class
identity does not survive capnweb), exactly five codes (NOT_FOUND,
FORBIDDEN, CONFLICT, BAD_REQUEST, INTERNAL; no UNAUTHORIZED — auth is a
transport 401 at connect), existence masking preserved (missing and
forbidden projects both answer byte-identical NOT_FOUND), and
tag-don't-redact: the /api/itx sessions' onSendError rewrites every
non-ItxError to INTERNAL keeping message + stack, which also opts stacks
into transmission.
- handle.ts / streams-capability.ts kernel throws converted to coded
ItxErrors with details ({ projectIdOrSlug }, { path, policyMode }, ...)
- fetch.ts: newItxRpcResponse dispatcher (capnweb's wrapper takes no
RpcSessionOptions); /api/itx and /api/itx/run HTTP error bodies carry
the code; run isolate threads a thrown ItxError's code into its JSON
- react client: message-shape regex deleted; getItxErrorCode /
isItxAccessError re-exported from the kernel module; useItxQuery
retries only code-less or INTERNAL errors (once); stream-tail keeps
skipping retry exactly for access errors
- tests: code-based unit tests incl. simulated capnweb crossing and
own-enumerability; worker harness proves code/details survive real
Workers RPC hops; e2e asserts projects.get of a missing project
rejects ItxError/NOT_FOUND over live capnweb
- docs: DECISIONS.md D18; oRPC replacement plan updated
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
jonastemplestein
added a commit
that referenced
this pull request
Jun 10, 2026
Conflict resolution and follow-ups: - itx-stream-subscribe harness/test: keep main's ItxError appendOutsidePolicy surface (#1456) alongside this branch's getState-based child-path tests (list() stays removed) - codemode-mcp-provider-stack e2e (Bugbot): ctx.os only forwards unary project.* oRPC procedures, so ctx.os.streams.get("/").getState() could never resolve — use project.streams.read({ streamPath: "/" }) instead (this test is skipped in CI, so the green check never exercised it) - itx REPL ambient typings: drop streams.list() — the procedure no longer exists on this branch Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
jonastemplestein
added a commit
that referenced
this pull request
Jun 10, 2026
capnweb's receiver rebuilds a plain Error — custom names and class identity never survive the wire, which is exactly why D18 makes detection duck-typed. The e2e contradicted its own doc comment by asserting error.name === "ItxError"; it now asserts getItxErrorCode + details, the actual contract. (This assertion also failed inside PR #1456's Preview e2e job, which nevertheless reported success — the preview runner swallowing a suite failure is a separate problem, recorded in the PR thread.) Also gives the two-event /api/itx/run record test 90s: the cold first run of isolate + stream DO on a fresh preview blew the 45s default and passed on the in-job retry at 12s. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
jonastemplestein
added a commit
that referenced
this pull request
Jun 10, 2026
…txError test fix
- Single-flight ensureItxContext in the Agent DO and MCP connection
(Bugbot High: wake-time workspace prep vs script runs could mint two
context ids; concurrent exec_js likewise).
- MCP session seeding gains MCP_CONTEXT_CAPS_VERSION (same re-seed-on-
version-bump semantics the agent already had).
- runItxScript gains convention: "ctx" — agent/LLM scripts (async (ctx)
=> …) are invoked directly, killing the async ({ itx, vars }) wrapper
so the execution record carries exactly what the model wrote. vars is
an "itx"-convention concern only.
- ItxError e2e test corrected: capnweb 0.8.0 reconstructs unknown error
names as plain Error and DROPS the name (ERROR_TYPES[name] || Error;
props loop skips "name"), so name identity is untransmittable — the
test (which merged in #1456 with its e2e check skipped, so it never
ran) now asserts the duck-typed code/details contract; errors.ts doc
corrected to match reality.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This was referenced Jun 10, 2026
jonastemplestein
added a commit
that referenced
this pull request
Jun 10, 2026
The preview e2e caught a real regression shipped in #1456: capnweb's receiver rebuilds `new Error(message)` and never assigns the custom name (verified in the 0.8.0 deserializer and against a live preview), so the `name === "ItxError"` gate rejected every wire-crossed kernel error — getItxErrorCode returned undefined, access errors were retried again, and the access-denied UI never fired. The unit suite missed it because its simulated crossing unfaithfully copied the name. Detection is now code-only (the five-code set; foreign code strings like ENOENT are outside it), the simulation matches the real receiver (name comes back "Error" and a test pins that), and the doc comments record why the name must not participate. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Replaces the message-shape regex error detection in the itx react client with structured
ItxErrors thrown by the kernel and read back by code, end to end across capnweb. Immediate cutover: server and client deploy together; the regex is gone.Design
apps/os/src/itx/errors.ts(new, transport-agnostic):ItxError extends Errorwith own enumerablecodeand optionaldetails— exactly the properties capnweb (0.8.0) serializes (["error", name, message, stack?, props?]). The receiver reconstructs a plainError, so detection is duck-typed viagetItxErrorCode(error)— neverinstanceof. No rehydration layer.NOT_FOUND,FORBIDDEN,CONFLICT,BAD_REQUEST,INTERNAL. No UNAUTHORIZED — itx auth happens at connect (Law 3), so auth failures are transport-level 401s before a session exists.itx.projects.get/ context resolution answer byte-identicalNOT_FOUNDfor missing AND forbidden, so error shapes can't be used to probe which project ids/slugs exist.FORBIDDENonly where existence is established or not secret (global streams, append policy, create/remove projects)./api/itxsessions getonSendError: tagOutboundItxError— every outbound non-ItxError becomesItxError { code: "INTERNAL" }with the original message and stack preserved; returning the error from the hook is also what opts the stack into transmission (we trust our callers). capnweb'snewWorkersRpcResponsewrapper takes no options, sofetch.tsre-implements its two-line dispatch asnewItxRpcResponse.detailsships in v1: throw sites attach what they have ({ projectIdOrSlug },{ path, policyMode }, conflict slugs/ids)./api/itx/run: HTTP error bodies now carrycode(400/403/404/500/503); the script isolate threads a thrown ItxError'scodethrough its JSON outcome.useItxQueryretries only code-less (socket) orINTERNALerrors, at most once; the stream-tail multiplexer keeps skipping retry exactly for access errors (NOT_FOUND/FORBIDDEN).Tests
react/errors.test.tsrewritten: code-based detection, own-enumerability ofcode/details(the load-bearing wire property), simulated capnweb crossing (instanceof lost, code/details survive),tagOutboundItxError.stream-tail.test.ts: access-error case now throws the post-capnweb shape (plain Error + name/code).pnpm test:itx-stream-subscribe): new case provescode/detailssurvive real Workers RPC hops (StreamsCapability → loopback → harness → test) — 9/9 pass, so kernel throws born behind the loopback keep their codes on the way to capnweb.itx.e2e.test.ts):itx.projects.get("definitely-not-a-project")rejects with nameItxError, codeNOT_FOUND, details — runs against a deployment in preview CI.Docs
ItxError(wire mechanics, taxonomy, masking, posture) and theonSendErrorwiring.DECISIONS.mdD18; oRPC replacement plan: kernel-hardening item recorded as done, "Error opacity" risk removed; task checkbox ticked.Verification
pnpm typecheck && pnpm lint && pnpm format && pnpm testall green at repo root;pnpm test:itx-stream-subscribe9/9.🤖 Generated with Claude Code
Note
Medium Risk
Touches auth-sensitive error shapes (existence masking), all /api/itx RPC sessions, and client retry behavior; coordinated deploy required but well-tested across RPC boundaries.
Overview
Introduces
ItxErrorwith five codes (NOT_FOUND,FORBIDDEN,CONFLICT,BAD_REQUEST,INTERNAL) as own enumerable props so capnweb can serialize them; clients detect errors viagetItxErrorCode/isItxAccessError, notinstanceofor message regexes.Kernel throw sites in
handle.ts,streams-capability.ts, and related paths now raiseItxErrorwith masking preserved (NOT_FOUNDfor missing and forbidden projects).fetch.tswiresonSendError: tagOutboundItxErrorthrough a customnewItxRpcResponse(non-ItxErrors becomeINTERNALwith stack); HTTP/api/itx/runand connect failures return JSONcodefields. Script runner threadscodethrough isolate JSON outcomes.React layer drops regex-based access-error detection;
useItxQueryretries only code-less orINTERNALerrors; stream-tail tests use post-capnweb error shapes. Docs (D18, plan, teardown task) mark kernel error hardening done. New e2e and worker-harness tests assertcode/detailssurvive capnweb and Workers RPC.Reviewed by Cursor Bugbot for commit 7661b13. Bugbot is set up for automated code reviews on this repo. Configure here.
Environment Config Lease
No active environment config lease.
OS
Status: released
Commit:
7661b13Preview: https://os.iterate-preview-3.com
Summary: Preview app released.
Workflow run
Updated: 2026-06-10T14:45:38.214Z