neon-bindings/neon · error · TypeError
expected JsTypedArray
Error message
expected JsTypedArray<T>
What it means
This error is returned by the `TryFromJs` impl for `Vec<u8>` (and typed-array-backed slices): the JS value must downcast to `JsTypedArray<T>`. The message "expected JsTypedArray<T>" fires when the value is not a JS typed array view — ArrayBuffers, Buffers (which are Uint8Array but not detected as a generic typed array here), objects, null, or undefined fail the downcast.
Solutions
- Pass a typed array view: `new Uint8Array(arrayBuffer)` instead of the ArrayBuffer itself
- Use `Buffer.from(x)` / `new Uint8Array(x)` in JS to build a typed array before calling
- Loosen the Rust parameter to a type accepting all binary shapes, or validate and convert in JS first
Example fix
// before (JS) native.sumBytes(await file.arrayBuffer()); // after (JS) native.sumBytes(new Uint8Array(await file.arrayBuffer()));
Defensive patterns
Strategy: type-guard
Validate before calling
function isTypedArray(x) { return ArrayBuffer.isView(x) && !(x instanceof DataView); } Type guard
function isTypedArray(v) { return v !== null && v !== undefined && ArrayBuffer.isView(v) && !(v instanceof DataView); } Try / catch
try { native.sumBytes(arg); } catch (e) { if (String(e).includes('expected JsTypedArray')) { native.sumBytes(new Uint8Array(arg instanceof ArrayBuffer ? arg : arg.buffer)); } else { throw e; } } Prevention
- Always pass typed arrays (Uint8Array etc.), never raw ArrayBuffers or DataViews
- Use ArrayBuffer.isView() as a cheap pre-call check
- Wrap ArrayBuffer in new Uint8Array(...) when the source is a blob or file
- Null-check optional binary arguments before the native call
When it happens
Trigger: Calling an exported Neon function whose parameter extracts as a typed-array-backed `Vec`/slice with a non-typed-array argument: raw ArrayBuffer, DataView, plain object, null, undefined.
Common situations: Passing `ArrayBuffer` directly instead of a view over it; passing a Node Buffer created via a path the downcast rejects; passing null for a supposed-optional binary argument.
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 JsBuffer
- 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/972f179064152b1b.
Report an issue: GitHub.
Appendix: source
Thrown at crates/neon/src/types_impl/extract/buffer.rs:109
fn try_into_js(self, cx: &mut Cx<'cx>) -> JsResult<'cx, Self::Value> {
JsTypedArray::from_slice(cx, self.as_slice())
}
}
impl<'cx, T> TryFromJs<'cx> for Vec<T>
where
JsTypedArray<T>: Value,
T: Binary,
{
type Error = TypeExpected<JsTypedArray<T>>;
fn try_from_js(
cx: &mut Cx<'cx>,
v: Handle<'cx, JsValue>,
) -> NeonResult<Result<Self, Self::Error>> {
let v = match v.downcast::<JsTypedArray<T>, _>(cx) {
Ok(v) => v,
Err(_) => return Ok(Err(Self::Error::new())),
};
Ok(Ok(v.as_slice(cx).to_vec()))
}
}
impl<T> private::Sealed for Vec<T>
where
JsTypedArray<T>: Value,
T: Binary,
{
}
impl<'cx, T, const N: usize> TryIntoJs<'cx> for [T; N]
where
JsTypedArray<T>: Value,
T: Binary,
{View on GitHub (pinned to 38960e4381)