napi-rs/napi-rs · error
async runtime generation task id space exhausted
Error message
async runtime generation task id space exhausted
What it means
The runtime allocates per-task ids from a monotonically increasing `next_task_id` within the current generation. When spawning a task would overflow the id counter, the runtime panics (after dropping the state guard) rather than reusing ids, since abort-handle bookkeeping depends on unique ids. Effectively unreachable defensive code.
Solutions
- Restart the process or recreate the runtime to start a new generation.
- In tests, reduce spawn counts or reset the generation counter.
- Report upstream if hit — a real hit indicates a generation-rotation bug.
Defensive patterns
Strategy: retry
Validate before calling
// Not guardable; requires ~2^64 spawns in one runtime generation. // Recreate the runtime long before id exhaustion.
Try / catch
std::panic::catch_unwind(|| runtime.spawn(task)).unwrap_or_else(|_| recreate_runtime());
Prevention
- Periodically recreate the runtime in extremely long-lived processes
- Never inject u64::MAX into next_task_id in tests
- Report any real occurrence upstream
When it happens
Trigger: Spawning a task (via the runtime's task-spawn path that inserts into `abort_handles`) when `next_task_id` has reached `u64::MAX` within one runtime generation — i.e. ~2^64 spawns without resetting the runtime generation.
Common situations: Never in normal apps; only fuzzing, synthetic tests saturating the counter, or extremely long-lived runtimes with astronomically many spawns.
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
- runtime metrics reset generation space exhausted
- {error}
- {}
- Share the same data between different buffers is not…
- Share the same data between different buffers is not…
AI-assisted analysis of napi-rs/napi-rs@39bd1205e4 (2026-09-13).
Data as JSON: /api/errors/ef58de96c36cddf2.
Report an issue: GitHub.
Appendix: source
Thrown at crates/async-runtime/src/async_runtime.rs:2658
abort_handles: FxHashMap::default(),
}),
idle: Condvar::new(),
})
}
fn try_register_async(self: &Arc<Self>) -> Option<(AbortRegistration, GenerationWorkGuard)> {
let (abort_handle, abort_registration) = AbortHandle::new_pair();
let mut state = self
.state
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
if state.closed {
return None;
}
let task_id = state.next_task_id;
let Some(next_task_id) = state.next_task_id.checked_add(1) else {
drop(state);
panic!("async runtime generation task id space exhausted");
};
state.next_task_id = next_task_id;
state.active += 1;
state.abort_handles.insert(task_id, abort_handle);
Some((
abort_registration,
GenerationWorkGuard {
work: Arc::clone(self),
task_id: Some(task_id),
},
))
}
fn try_register_work(self: &Arc<Self>) -> Option<GenerationWorkGuard> {
let mut state = self
.state
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);View on GitHub (pinned to 39bd1205e4)