tokio-rs/tokio · error · io::Error
signal too large
Error message
signal too large
What it means
signal_enable returns 'signal too large' when globals().storage().get(signal as EventId) returns None — the internal per-signal storage array has no slot for the requested number, meaning it exceeds the compiled maximum signal index tokio tracks.
Source
Thrown at tokio/src/signal/unix.rs:284
///
/// This will register the signal handler if it hasn't already been registered,
/// returning any error along the way if that fails.
fn signal_enable(signal: SignalKind, handle: &Handle) -> io::Result<()> {
let signal = signal.0;
if signal <= 0 || signal_hook_registry::FORBIDDEN.contains(&signal) {
return Err(Error::new(
ErrorKind::Other,
format!("Refusing to register signal {signal}"),
));
}
// Check that we have a signal driver running
handle.check_inner()?;
let globals = globals();
let siginfo = match globals.storage().get(signal as EventId) {
Some(slot) => slot,
None => return Err(io::Error::new(io::ErrorKind::Other, "signal too large")),
};
siginfo
.init
.get_or_init(|| {
unsafe { signal_hook_registry::register(signal, move || action(globals, signal)) }
.map(|_| ())
.map_err(|e| e.raw_os_error())
})
.map_err(|e| {
e.map_or_else(
|| Error::new(ErrorKind::Other, "registering signal handler failed"),
Error::from_raw_os_error,
)
})
}
/// An listener for receiving a particular type of OS signal.View on GitHub (pinned to 625954f365)
Solutions
- Use standard signals (<= 31 on Linux) which always fit.
- Check the signal number is below NSIG/signal_hook_registry's maximum before registering.
- Upgrade tokio — newer versions may expand the supported range.
- For real-time signals, confirm the specific number fits within tokio's storage.
Example fix
// before
let s = signal(SignalKind::from_raw(60))?; // may exceed storage
// after
let num = 60;
if num >= libc::NSIG { return Err(io::Error::new(io::ErrorKind::Other, "signal too large")); }
let s = signal(SignalKind::from_raw(num))? Defensive patterns
Strategy: validation
Validate before calling
if num as usize >= libc::NSIG {
return Err(io::Error::new(io::ErrorKind::Other, "signal too large"));
}
signal(SignalKind::from_raw(num))? Type guard
fn within_signal_storage(sig: i32) -> bool {
sig > 0 && (sig as usize) < libc::NSIG
} Try / catch
match signal(SignalKind::from_raw(num)) {
Ok(s) => s,
Err(e) if e.to_string().contains("signal too large") => return Err(e),
Err(e) => return Err(e),
} Prevention
- Stick to standard signals (<= 31 on Linux).
- Validate against NSIG before using real-time signals.
- Upgrade tokio for wider signal storage support.
When it happens
Trigger: Calling unix::signal with a signal number larger than tokio's compiled signal storage capacity (NSIG-derived upper bound).
Common situations: Using real-time signals (SIGRTMIN+n) on platforms where the number exceeds tokio's slot count; passing a very large platform-specific signal constant; miscomputing a signal offset.
Related errors
- Refusing to register signal {signal}
- registering signal handler failed
- signal driver gone
- there is no signal driver running, must be called from the c
- not a pipe
AI-assisted analysis of tokio-rs/tokio@625954f365 (2026-08-11).
Data as JSON: /api/errors/6d66d3a242625c33.
Report an issue: GitHub.