Skip to content

fix(backend-native): unguarded .unwrap() in js_stream_push_chunk#10882

Open
tlangton3 wants to merge 1 commit into
cube-js:masterfrom
tlangton3:cube/fix-backend-native-stream-chunk-transform-panic
Open

fix(backend-native): unguarded .unwrap() in js_stream_push_chunk#10882
tlangton3 wants to merge 1 commit into
cube-js:masterfrom
tlangton3:cube/fix-backend-native-stream-chunk-transform-panic

Conversation

@tlangton3
Copy link
Copy Markdown
Contributor

@tlangton3 tlangton3 commented May 14, 2026

Summary

Replaces an unguarded .unwrap() in the JS-Rust streaming bridge (js_stream_push_chunk) with a reject()-based error flow.

The .unwrap() is only reachable if a driver pushes a chunk shape that fails JsValueObject::get's primitive-type extraction (e.g. a JS array where the schema declares a primitive). Well-behaved drivers don't currently exercise this path. When it does fire, Neon's panic-recovery wrapper hides the underlying CubeError message — callers see "internal error in Neon module: called Result::unwrap()..." instead of the actual cause. Panicking across the Neon FFI boundary is also an undesirable class of bug independent of practical reachability.

Found while investigating #10875 (the actual fix for that is in #10877).

Changes

Replaced the .unwrap() with an error arm that:

  • Calls JsWriteStream::reject(err_msg) to surface the error through the Rust mpsc channel to the wire layer.
  • Resolves the JS per-chunk callback via wait_for_future_and_execute_callback to prevent the Node side from hanging. Both notifications are required here to satisfy both ends of the FFI bridge.

Testing

Added FakeMalformedRowStream to test/response-fake.ts to push a chunk with invalid nested arrays. The new test (does not crash node when a stream chunk fails to transform) verifies that the underlying error reaches the wire cleanly without triggering Neon's panic-recovery wrapper.

…m to UserError via reject

`js_stream_push_chunk` in the JS-Rust streaming bridge previously
called `.unwrap()` on the result of `transform_response`. If the chunk
pushed from JS contained a value of an unexpected shape (e.g. a JS
array where a primitive was expected), `transform_response` returned
`Err` and `.unwrap()` panicked inside Neon's bridge context — Neon
recovers the panic by surfacing it as `"internal error in Neon
module: called Result::unwrap()..."` rather than the underlying error
message, and depending on the surrounding JS state can leak an
unhandled rejection on Node's tick queue.

This is distinct from cube-js#10875's BigQuery production crash (which fires
upstream of `js_stream_push_chunk` and is fixed in a sibling commit
to `BigQueryDriver.stream`). It is, however, a separate latent panic
vector across the FFI boundary that's worth hardening — the kind of
"theoretical bomb" the next driver to mis-shape a chunk would
detonate.

Replaces the `.unwrap()` with a match arm that:
  - calls `JsWriteStream::reject(err_msg)` so the error flows through
    the existing mpsc channel and the wire layer can emit a structured
    Postgres `ErrorResponse`,
  - routes the JS-side per-chunk callback through the same
    `wait_for_future_and_execute_callback` wrapper used on the success
    path so async-callback timing is consistent (no Zalgo).

Adds a regression test (`does not crash node when a stream chunk
fails to transform`) using a synthetic `FakeMalformedRowStream` that
pushes a chunk whose field values are nested arrays — guaranteed to
fail `JsValueObject::get` and exercise the new error arm. Verified
the test fails when the fix is reverted (Neon's panic-wrapper string
appears in the wire output) and passes with the fix (the underlying
transform error reaches the client cleanly).
@github-actions github-actions Bot added rust Pull requests that update Rust code javascript Pull requests that update Javascript code pr:community Contribution from Cube.js community members. labels May 14, 2026
@tlangton3 tlangton3 changed the title fix(backend-native): convert .unwrap() panic in stream chunk transform to UserError via reject fix(backend-native): unguarded .unwrap() in js_stream_push_chunk May 18, 2026
@tlangton3 tlangton3 marked this pull request as ready for review May 20, 2026 14:48
@tlangton3 tlangton3 requested a review from a team as a code owner May 20, 2026 14:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

javascript Pull requests that update Javascript code pr:community Contribution from Cube.js community members. rust Pull requests that update Rust code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant