{"record":{"id":"50cf2752c092e0d1","repo":"napi-rs/napi-rs","slug":"failed-to-schedule-readablestream-read","errorCode":null,"errorMessage":"Failed to schedule ReadableStream read","messagePattern":"Failed to schedule ReadableStream read","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/napi/src/bindgen_runtime/js_values/stream/read.rs","lineNumber":789,"sourceCode":"            }\n          }\n          Ok(())\n        },\n      );\n      // The threadsafe call itself can fail to schedule (runtime shutting down /\n      // `Status::Closing`, or a full queue). When it does, the callback above never\n      // runs, so `reading`/`waker` would be stuck. Recover synchronously: clear the\n      // flag, end the stream, and surface the error now.\n      if status != Status::Ok {\n        let mut inner = self\n          .state\n          .inner\n          .lock()\n          .map_err(|_| Error::new(Status::InvalidArg, \"Poisoned lock in Reader::poll_next\"))?;\n        inner.reading = false;\n        inner.done = true;\n        inner.waker = None;\n        return Poll::Ready(Some(Err(Error::new(\n          status,\n          \"Failed to schedule ReadableStream read\",\n        ))));\n      }\n    }\n\n    Poll::Pending\n  }\n}\n\n/// Shared state for ReadableStream that coordinates between pull and cancel callbacks.\n/// Uses Arc to share ownership between callbacks, Mutex to protect the stream,\n/// and AtomicBool for lock-free cancellation checks.\n///\n/// Memory management: The Arc is freed by a invoke when the underlying_source\n/// object is garbage collected. Callbacks only \"borrow\" the Arc using the\n/// increment+from_raw pattern, never freeing it directly. This prevents\n/// use-after-free if cancel_callback is invoked after pull_callback has","sourceCodeStart":771,"sourceCodeEnd":807,"githubUrl":"https://github.com/napi-rs/napi-rs/blob/39bd1205e480a453a2da2601a760bde5a71ed016/crates/napi/src/bindgen_runtime/js_values/stream/read.rs#L771-L807","documentation":"This error is returned from `Reader::poll_next` when the N-API call that schedules an async read on the underlying ReadableStream returns a non-Ok status. The stream is terminated (`done = true`) and the raw scheduling status is surfaced with this message. It means the runtime refused to start the read operation, not that the stream itself errored.","triggerScenarios":"Calling next()/poll_next on a stream obtained from a ReadableStream when the scheduling napi call fails — e.g. an exception is pending in the environment, the env is shutting down, or an invalid status is returned by the runtime.","commonSituations":"Awaiting the stream inside a context with a pending uncaught JS exception; using the Reader during process/env teardown; embedding Node with mismatched or failing N-API environment.","solutions":["Inspect the attached `status` field for the exact N-API failure code","Clear or handle any pending JS exception before polling the stream","Ensure the Reader is polled while the environment is alive and on the JS thread","Upgrade/verify Node version and N-API compatibility of the embedding"],"exampleFix":"// before\nwhile let Some(v) = stream.next().await { ... } // pending exception present\n// after\n// (JS side) ensure prior awaited code did not throw before consuming the stream\ntry { for await (const c of readable) {} } catch (e) { /* handle */ }","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"// Rust: check terminal state before polling again\nif reader_is_done(&stream) { return; }","tryCatchPattern":"match stream.next().await { Err(e) if e.message == \"Failed to schedule ReadableStream read\" => { inspect(e.status); stop_polling(); } , other => other }","preventionTips":["Ensure no pending JS exception exists before consuming the stream","Only poll during normal env lifetime, not teardown","Verify N-API version compatibility of the runtime"],"tags":["stream","readable-stream","scheduling","napi"],"backgroundTag":"unsupported-operation","analyzedSha":"39bd1205e480a453a2da2601a760bde5a71ed016","analyzedAt":"2026-09-13T20:31:47.814Z","contentChangedAt":"2026-09-13T20:31:47.814Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}