noctcore-async-safety/forward-abort-signal
A function that accepts an
AbortSignalbut never forwards it to the work it awaits leaves that work uncancellable.
Recommended preset: error · Autofix: no · Suggestions: no · Type information: not needed
Threading an AbortSignal through a call graph is only useful if every layer passes it down. A function that
takes a signal, maybe checks signal.aborted, but then awaits a fetch/call without passing the signal
along has a dead parameter: callers think they can cancel, but the actual I/O ignores them. The cancel never
reaches the socket.
What it flags
Section titled “What it flags”A function (declaration, expression, or arrow) that:
- accepts an AbortSignal-shaped parameter — named
signal, typedAbortSignal, or the destructured{ signal }form; and - contains an awaited call or a
fetch(...)(something that could have received the signal); and - never forwards the signal — every use is a member-access check (
signal.aborted,signal.throwIfAborted()), or it is unused.
“Forwarding” is deliberately generous: passing the signal as an argument, into an options object, assigning it, or returning it all count — so the rule errs toward silence rather than false positives.
// signal accepted, fetch left uncancellableasync function load(url: string, signal: AbortSignal) { return await fetch(url);}// signal forwardedasync function load(url: string, signal: AbortSignal) { return await fetch(url, { signal });}What it does not flag
Section titled “What it does not flag”- A function with no awaited call or
fetch(e.g. a purewhile (!signal.aborted)polling loop) — there is nothing to forward to. - A signal forwarded in any form: as a call argument, into an options object (
{ signal }or{ signal: sig }under another parameter name), or from inside a nested callback such as a.map. - A function with no signal-shaped parameter.
When not to use it
Section titled “When not to use it”If you deliberately accept a signal only to poll .aborted in a compute loop with no downstream call, this rule
will still fire when that loop awaits something (a sleep, say) that cannot accept a signal. Disable it inline
for those functions.