neon-bindings/neon · error · TypeError
expected JsBuffer
Error message
expected JsBuffer
What it means
This is the extraction error produced when `JsValue` cannot be downcast to `JsArrayBuffer` while extracting an `ArrayBuffer` argument in a Neon exported function. The `TryFromJs` impl for `ArrayBuffer<B>` returns `Self::Error` (whose message is "expected JsBuffer") when the incoming JS value is not an ArrayBuffer (detached views, plain objects, typed arrays, strings, etc. all fail).
Solutions
- Convert the JS value to a real ArrayBuffer before calling: `value.buffer` for typed arrays or `Uint8Array.from(buffer)` for Buffers
- Change the Rust signature to accept `JsBuffer`/`Buffer` if callers pass Node Buffers
- Accept a broader type in Rust (`&[u8]` via `JsTypedArray`) or handle the error in JS and retry with a converted value
Example fix
// before (JS)
const { readChunk } = require('./native');
readChunk(Buffer.from('data'));
// after (JS)
const buf = Buffer.from('data');
const ab = buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
readChunk(ab); Defensive patterns
Strategy: type-guard
Validate before calling
function isArrayBuffer(x) { return x instanceof ArrayBuffer; } Type guard
function isRealArrayBuffer(v) { return v !== null && v !== undefined && v instanceof ArrayBuffer; } Try / catch
try { native.readChunk(arg); } catch (e) { if (String(e).includes('expected JsBuffer')) { native.readChunk(toArrayBuffer(arg)); } else { throw e; } } Prevention
- Ensure JS callers pass true ArrayBuffer instances, not Node Buffer or typed arrays
- Wrap args: `x instanceof ArrayBuffer ? x : x.buffer` before calling
- Keep Rust and JS argument types in sync when refactoring the API
- Document the expected binary type on each exported function
When it happens
Trigger: Calling an exported Neon function whose parameter extracts as `ArrayBuffer` with an argument that is not a JS ArrayBuffer: a Buffer, Uint8Array, plain object, null, undefined, or a string.
Common situations: Passing a Node Buffer or Uint8Array from JS where the Rust signature expects `ArrayBuffer`; sending `null`/`undefined`; a caller on the JS side changed the value's type after a refactor.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- expected JsTypedArray
- class must be implemented for a type name
- try_catch: unexpected Err(Throw) when VM is not in a…
- The `neon::main` macro must only be used once
- Attempted to dereference a `neon::handle::Root` from the…
AI-assisted analysis of neon-bindings/neon@38960e4381 (2026-09-13).
Data as JSON: /api/errors/7f7da56d1ec00748.
Report an issue: GitHub.
Appendix: source
Thrown at crates/neon/src/types_impl/extract/buffer.rs:29
},
};
/// Wrapper for converting between bytes and [`JsArrayBuffer`](JsArrayBuffer)
pub struct ArrayBuffer<B>(pub B);
impl<'cx, B> TryFromJs<'cx> for ArrayBuffer<B>
where
for<'b> B: From<&'b [u8]>,
{
type Error = TypeExpected<JsBuffer>;
fn try_from_js(
cx: &mut Cx<'cx>,
v: Handle<'cx, JsValue>,
) -> NeonResult<Result<Self, Self::Error>> {
let v = match v.downcast::<JsArrayBuffer, _>(cx) {
Ok(v) => v,
Err(_) => return Ok(Err(Self::Error::new())),
};
Ok(Ok(ArrayBuffer(B::from(v.as_slice(cx)))))
}
}
impl<'cx, B> TryIntoJs<'cx> for ArrayBuffer<B>
where
B: AsRef<[u8]>,
{
type Value = JsArrayBuffer;
fn try_into_js(self, cx: &mut Cx<'cx>) -> JsResult<'cx, Self::Value> {
JsArrayBuffer::from_slice(cx, self.0.as_ref())
}
}
impl<B> private::Sealed for ArrayBuffer<B> {}View on GitHub (pinned to 38960e4381)