Skip to content

fix: preserve Error cause graphs in structured clone - #192

Draft
fuller-stack-dev wants to merge 9 commits into
openclaw:mainfrom
fuller-stack-dev:claude/error-cause-structured-clone
Draft

fuller-stack-dev wants to merge 9 commits into
openclaw:mainfrom
fuller-stack-dev:claude/error-cause-structured-clone

Conversation

@fuller-stack-dev

@fuller-stack-dev fuller-stack-dev commented Oct 19, 2026 •

Copy link
Copy Markdown
Member

Summary

Preserve an Error's own data-descriptor cause through structuredClone, worker postMessage, bun:jsc, and node:v8 serialization. The previous terminal-Error writer silently dropped it, including shared memory nested inside it.

  • Move Error handling into the existing iterative graph walker and object pool, registering each Error before its cause so cycles and aliases survive.
  • Snapshot and GC-root the own data cause before name/message/stack metadata can execute user code; omit inherited/accessor causes without invoking getters and propagate nested serialization failures.
  • Use clone format version 15 with an explicit cause-presence byte. New readers retain version-14-and-earlier compatibility; old readers reject the new format rather than misreading it. Version 15 is emitted for all newly serialized values, even cause-free values. Upgrade readers before writers where persisted or exchanged bytes cross runtime versions; do not assume old runtimes can read newly persisted v15 data after rollback.
  • Traverse non-enumerable Error causes in the existing Buffer-tagging pass for node:v8/advanced IPC.
  • Preserve the separate bounded, best-effort worker-error metadata owner using SerializationContext::WorkerError. Normal cloning is lossless or fails; worker error events keep existing uncloneable/deep-cause behavior.
  • Keep shared-memory boundary semantics: structuredClone/worker messages share backing memory; default bun:jsc/node:v8 storage copies shared input into private ArrayBuffers.

Qualification at frozen head

Source head: a1ef1ee4bb2dc3e8dd76f3bd949680fffbff4954; tree: 037ac839d66c0ac748e9f8047e142964dd7180cc.

Native run 39188859210 is complete and successful on Linux x64 and macOS arm64, including native compilation and repository-selected compatibility tests. Both jobs compile GitHub merge revision 11e51ce92404738da0f51b7750c58163fd21d1ae; its tree exactly matches the frozen source head. It has parents 7bd4fdff3d4035bcea50718673c663f5474bae89 and the source head. Source lints, JavaScript lint, and Format also pass.

Local qualification used that run's exact macOS executable (SHA-256 d0909f169ff04810b51b5911a9cfaa715f98e95d832b27cc6114067a0f12d442), reporting Bun 1.4.4, the merge revision above, and WebKit f8521bb45429b3e1df6bc6d9b98b8df4376a89c5:

  • Same final regression bytes on frozen 67b55 versus this successor: 36 failed, 0 passed -> 36 passed, 0 failed. Covers name/message/stack replacement, deletion and uncloneable replacement; original uncloneable cause rejection; early-GC lifetime; and node:v8 Buffer brand/content.
  • Full three changed graph/Buffer/shared-memory suites: 464 passed, 0 failed, 9,229 assertions.
  • Existing worker error-event regressions: 8 passed, 0 failed, including bounded 10,000-deep and uncloneable causes.
  • Unchanged OpenClaw hook suite at 32f7724872fefb7994cd97dd7740ed42a6fa2c7b: 24/24 passed, including shared memory hidden in Error.cause.
  • Frozen unchanged pinned runtime 7bd4fdff3d4035bcea50718673c663f5474bae89 against the preceding 67b55 cause cases (historical evidence): 68 failed, 5 passed, 355 filtered. Those are the expected regression failures, not a claimed green baseline.
  • Node reference checks confirm descriptor/cycle/getter behavior, Buffer cause identity, ArrayBuffer transfer and failed-transfer atomicity. Local formatting/diff checks pass.

Coverage includes primitives and nested errors, aliases/cycles/reference-pool width changes, collection during traversal, accessor safety, nested exceptions, malformed/truncated records, old records, fresh processes, shared memory, transfer success and failure atomicity. All local runtime qualification uses preflight-verified task-private handoff SQLite paths; no live store is used.

Historical failures are retained: run 39182576950 exposed two current-engine API compile errors; successor run 39184230889 compiled both targets but exposed worker-error integration and an incorrect new storage-rejection expectation. The first independent review of 67b55 then reproduced metadata side effects replacing the cause before capture. This signed descendant snapshots and roots first using the existing GC buffer, removes the later redundant root, and supplies red/green regressions. It also corrects the old-reader wording on the current-runtime bare-framing test. These failures are fixed rather than waived. Existing platform skips/todos remain; a successful selected suite is not a claim that every upstream test ran.

Simplification and scope

The terminal Error writer/reader are replaced, not duplicated. Existing graph traversal, pools, GC rooting, transfer finalization and Buffer tagging own the behavior. Existing worker-error metadata remains its sole bounded owner. No new state store, dependency, WebKit pin, lockfile change, skipped test or relaxed guard.

Net delta against the pinned base: production +212/-122; tests +385/-5. Most production churn moves the existing Error metadata implementation into graph-aware helpers. Every test group covers a distinct observable boundary; no source-text mirror tests.

This is the runtime prerequisite for OpenClaw PR #175276. This successor is frozen for the same independent reviewer; the earlier CHANGES REQUESTED result is not treated as approval. PR artifacts are qualification inputs, not published release artifacts. No repaired runtime release, consumer pin update, or Odin deployment has occurred.

@autofix-troubleshooter

Copy link
Copy Markdown

Hi! I'm the autofix logoautofix.ci troubleshooter bot.

It looks like you correctly set up a CI job that uses the autofix.ci GitHub Action, but the autofix.ci GitHub App has not been installed for this repository. This means that autofix.ci unfortunately does not have the permissions to fix this pull request. If you are the repository owner, please install the app and then restart the CI workflow! 😃

This branch has not been deployed

No deployments
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.

2 participants