Skip to content

feat(runtimed-wasm): install console_error_panic_hook#2105

Merged
rgbkrk merged 5 commits intomainfrom
feat/wasm-panic-hook
Apr 23, 2026
Merged

feat(runtimed-wasm): install console_error_panic_hook#2105
rgbkrk merged 5 commits intomainfrom
feat/wasm-panic-hook

Conversation

@rgbkrk
Copy link
Copy Markdown
Member

@rgbkrk rgbkrk commented Apr 23, 2026

Summary

Install console_error_panic_hook::set_once() from a #[wasm_bindgen(start)] function so Rust panics inside WASM surface to console.error with file, line, message, and a Rust backtrace — instead of the opaque __wbg___wbindgen_throw_6b64449b9b9ed33c stack the frontend sees today.

Why now

Post-#2103, Smoke / Deno / UI (Cell Visibility) E2E specs all go green. But UV Pyproject and UV Prewarmed still show the App ErrorBoundary fallback. The last lines of e2e-logs/app.log from those runs look like this:

[WARN] webview: [sync-engine] receive_frame failed:
  __wbg___wbindgen_throw_6b64449b9b9ed33c@...
  (null)@<?>:wasm-function[8514]
  (null)@<?>:wasm-function[8380]
  ...

That's a Rust panic bridged through wasm-bindgen's throw_str. We can't read it — no file, no line, no message. The specs that fail are the ones that auto-launch a kernel against a fixture with pyproject.toml, so the daemon's RuntimeStateDoc walks through the full lifecycle (NotStarted → Resolving → PreparingEnv → Launching → Connecting → Running(Idle)). Empty-notebook specs never drive the state doc through those transitions, which is why they survived.

Combined with #2101 (ErrorBoundary → host logger), the next failing CI run will emit both the React component stack and the Rust panic payload into e2e-logs/app.log. Then we can fix the actual bug.

Changes

  • crates/runtimed-wasm/Cargo.toml — add console_error_panic_hook = "0.1".
  • crates/runtimed-wasm/src/lib.rs#[wasm_bindgen(start)] pub fn __wasm_start() { console_error_panic_hook::set_once(); }. Runs exactly once at module init, before any NotebookHandle is constructed.
  • Rebuilds apps/notebook/src/wasm/runtimed-wasm/ to pick up the wiring.

Test plan

rgbkrk added 4 commits April 23, 2026 07:45
Design for dx emitting a Parquet head + a pull handle for
incremental Arrow IPC continuation, so huge DataFrames render
a first screenful immediately and grow in place.

Key shape:
- Head: 100-ish rows serialized as Parquet through the existing
  dx path. Sift's existing load hits immediately.
- Continuation: new `nteract.dx.stream.<id>` comm. Runtime agent
  pulls Arrow IPC chunks outside the execution-message hot path
  and appends them as blob refs in a new manifest field on the
  same output id.
- Transport is shared with #1815 (query backend).
- No mutable blobs, no ContentRef shape change — chunks are a
  JSON list of existing blob refs inside the manifest.
- Late joiners replay from the CRDT because chunks go through
  normal sync, not a side channel.
- RuntimeStateDoc moved from notebook-doc to runtime-doc (#2056)
- CRDT writes go through RuntimeStateHandle (#2059)
- Pull task uses fork()/merge() for async blob work
- Dead broadcasts removed (#2065) - manifest updates propagate via CRDT
- Updated review pointers to current file paths
The namespace rule moved out of CLAUDE.md and now lives in
.claude/rules/architecture.md § "Reserved Comm Namespace:
`nteract.dx.*`". Update the two spec references to point there.

No change to the design itself.
Rust panics inside WASM currently surface to the frontend as an opaque
`__wbg___wbindgen_throw_6b64449b9b9ed33c` stack with wasm-function
indices and no file/line. The error reaches the App ErrorBoundary and
the "Something went wrong" fallback renders, but the cause is
invisible in packaged / CI builds.

This is exactly what's happening on UV Pyproject + UV Prewarmed E2E
today (post-#2103): something in the runtime-doc read path panics
when the daemon syncs a RuntimeState that walks through the full
lifecycle starting → running, and we have no way to name it.

Install `console_error_panic_hook::set_once()` from a
`#[wasm_bindgen(start)]` function so it runs exactly once before
any `NotebookHandle` is constructed. Panics now log with file, line,
message, and a Rust backtrace.

Combined with #2101 (ErrorBoundary → host logger), the next failing
E2E run will emit both the React component stack and the Rust panic
payload into `e2e-logs/app.log`.

Rebuilds the WASM bundle to pick up the hook wiring.

Verification:
- `cargo xtask wasm runtimed` — succeeds
- `deno test --allow-read crates/runtimed-wasm/tests/` — shape test
  still passes (51 filtered + 1 ok, the expected set)
@github-actions github-actions Bot added documentation Improvements or additions to documentation sync Automerge CRDT sync protocol frontend Webview, React, TypeScript UI labels Apr 23, 2026
The wasm panic hook from the previous commit calls `console.error`.
In dev builds `attachConsole()` from tauri-plugin-log is DEV-only
(see packages/notebook-host/src/tauri/index.ts:280), and the plugin
only bridges Rust log output INTO the browser console — it doesn't
forward browser console OUT to Rust. In packaged / CI builds the
panic message goes to `console.error` and stops there.

Install a small forwarder in main.tsx: wrap `console.error` to also
call `logger.error` (host-log). WASM panics now land in notebook.log
alongside everything else, visible in CI's `e2e-logs/app.log`.

Preserves the original console.error behavior so devtools stays
unchanged. The forwarding call is in a try/catch so a logger failure
can't swallow the original error.
@rgbkrk rgbkrk merged commit 1c53cd1 into main Apr 23, 2026
17 checks passed
@rgbkrk rgbkrk deleted the feat/wasm-panic-hook branch April 23, 2026 15:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation frontend Webview, React, TypeScript UI sync Automerge CRDT sync protocol

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant