{"record":{"id":"690e6c3f43247610","repo":"neon-bindings/neon","slug":"failed-to-unwrap-napi-external-as-box-any","errorCode":null,"errorMessage":"Failed to unwrap napi_external as Box<Any>","messagePattern":"Failed to unwrap napi_external as Box<Any>","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/neon/src/types_impl/boxed.rs","lineNumber":214,"sourceCode":"    fn downcast<Other: Value>(cx: &mut Cx, other: &Other) -> Option<Self> {\n        let local = other.to_local();\n        let data = unsafe { maybe_external_deref(cx.env(), local) };\n\n        // Attempt to downcast the `Option<&BoxAny>` to `Option<*const T>`\n        data.and_then(|v| v.downcast_ref())\n            .map(|raw_data| Self(JsBoxInner { local, raw_data }))\n    }\n\n    fn to_local(&self) -> raw::Local {\n        self.0.local\n    }\n\n    unsafe fn from_local(env: Env, local: raw::Local) -> Self {\n        let raw_data = unsafe { maybe_external_deref(env, local) }\n            .expect(\"Failed to unwrap napi_external as Box<Any>\")\n            .downcast_ref()\n            .expect(\"Failed to downcast Any\");\n\n        Self(JsBoxInner { local, raw_data })\n    }","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/neon-bindings/neon/blob/38960e4381d9ad13b551cdf2d261f609167c9bc2/crates/neon/src/types_impl/boxed.rs#L196-L232","documentation":"`JsBox::from_local` converts a raw N-API local handle back into a `JsBox<T>`. It expects the handle's associated external data to be a `Box<dyn Any>` holding the boxed Rust value; the `.expect` fires when `maybe_external_deref` returns None — the local is not an napi_external carrying Neon's boxed data. This is an internal invariant violation: the handle was not created by `JsBox::new`, so the cast is invalid.","triggerScenarios":"`from_local` panics when unwrapping an `Option<Box<dyn Any>>` from `maybe_external_deref(env, local)` yields None — i.e. the raw local handle does not wrap a Neon-managed napi_external (wrong value type passed where a JsBox is expected).","commonSituations":"Passing a plain JS object, function, or a foreign external to an API that reconstructs a `JsBox<T>`; FFI/manual N-API code creating externals outside Neon; type confusion between native handles.","solutions":["Ensure the local handle originates from `JsBox::new`/Neon's boxing path","Use checked conversion APIs (e.g. `cx.argument::<JsBox<T>>(i)`) that return an error instead of unwrapping","Audit manual N-API/FFI code that attaches externals so it uses Neon's expected Box<Any> layout"],"exampleFix":"Only call `JsBox::from_local` (or APIs that go through it) on handles produced by `JsBox::new`; type-check with `cx.argument::<JsBox<T>>()` which validates instead of panicking.","handlingStrategy":"type-guard","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never construct napi_external values outside Neon's boxing helpers","Prefer `downcast` (which returns Option) over `from_local` when the value's type is uncertain"],"tags":[],"backgroundTag":null,"analyzedSha":"38960e4381d9ad13b551cdf2d261f609167c9bc2","analyzedAt":"2026-09-13T09:05:33.640Z","contentChangedAt":"2026-09-13T09:05:33.640Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}