neon-bindings/neon · error
u32 overflow ocurred in Lifecycle InstanceId
Error message
u32 overflow ocurred in Lifecycle InstanceId
What it means
Neon assigns every module instance a monotonically increasing `InstanceId` backed by a process-global `AtomicU32`. `next()` uses `checked_add` and panics if the counter would exceed `u32::MAX`. Reaching this requires billions of module-instance creations (e.g. many worker threads or repeated dlopen cycles) within one process, so the panic effectively signals runaway instance churn or counter corruption.
Solutions
- Reuse worker threads / a fixed thread pool instead of creating a new Worker (and thus a new module instance) per task.
- Load the addon once per process (module-level singleton) and share it across workers where possible.
- Profile and fix any code path that triggers instance data initialization on every call; initialization should happen once per instance.
- As a last resort, file/patch Neon to use u64 for the counter if your workload legitimately creates billions of instances.
Example fix
// before
for job in jobs {
let w = Worker::new(); // new module instance per job
w.run(job);
}
// after
let pool = ThreadPool::new(8); // fixed workers, one module instance
for job in jobs { pool.run(job); } Defensive patterns
Strategy: fallback
Validate before calling
// keep a process-level counter of worker/module loads in JS
let loads = (global.__addonLoads = global.__addonLoads || 0) + 1;
if (loads > 1e6) throw new Error('excessive addon instance churn'); Prevention
- Reuse a worker pool instead of creating Workers per task
- Load the addon once per process; avoid repeated dynamic load/unload
- Monitor worker spawn rates in long-running services
- Treat this panic as a symptom: fix the churn, don't catch it
When it happens
Trigger: Creating more than 2^32-1 Neon module instances in one process — typically a hot loop that spawns worker threads each loading the addon, or repeatedly loading/unloading the native module; also possible if instance data is re-initialized per call due to a bug.
Common situations: Thread-pool benchmarks or job systems that spawn a fresh Worker per task instead of reusing workers; test suites that load the addon in thousands of processes... or one process with per-test dynamic loads; a library embedding Neon that re-inits per request.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- Attempted to dereference a `neon::handle::Root` from the…
- 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
- Must call `into_inner` or `drop` on `neon::handle::Root`
AI-assisted analysis of neon-bindings/neon@38960e4381 (2026-09-13).
Data as JSON: /api/errors/196781d1f2dd9054.
Report an issue: GitHub.
Appendix: source
Thrown at crates/neon/src/lifecycle.rs:43
types::promise::NodeApiDeferred,
};
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(transparent)]
/// Uniquely identifies an instance of the module
///
/// _Note_: Since `InstanceData` is created lazily, the order of `id` may not
/// reflect the order that instances were created.
pub(crate) struct InstanceId(u32);
impl InstanceId {
fn next() -> Self {
static NEXT_ID: AtomicU32 = AtomicU32::new(0);
let next = NEXT_ID.fetch_add(1, Ordering::SeqCst).checked_add(1);
match next {
Some(id) => Self(id),
None => panic!("u32 overflow ocurred in Lifecycle InstanceId"),
}
}
}
/// `InstanceData` holds Neon data associated with a particular instance of a
/// native module. If a module is loaded multiple times (e.g., worker threads), this
/// data will be unique per instance.
pub(crate) struct InstanceData {
id: InstanceId,
/// Used to free `Root` in the same JavaScript environment that created it
///
/// _Design Note_: An `Arc` ensures the `ThreadsafeFunction` outlives the unloading
/// of a module. Since it is unlikely that modules will be re-loaded frequently, this
/// could be replaced with a leaked `&'static ThreadsafeFunction<NapiRef>`. However,
/// given the cost of FFI, this optimization is omitted until the cost of an
/// `Arc` is demonstrated as significant.
drop_queue: Arc<ThreadsafeFunction<DropData>>,View on GitHub (pinned to 38960e4381)