denoland/deno · error · AbortError
ABORT_ERR
ABORT_ERR
Error message
The operation was aborted
What it means
events.once(emitter, name, { signal }) throws or rejects with AbortError (ABORT_ERR, 'The operation was aborted') when the AbortSignal passed in options is already aborted at call time (synchronous throw at _events.mjs:937), or when it aborts later, because the internal abortListener rejects the pending promise with the same error. This mirrors Node's cooperative-cancellation contract for the events API: aborting the signal cancels the wait for the event. It signals deliberate cancellation, not an emitter bug.
Source
Thrown at ext/node/polyfills/_events.mjs:937
emitterOrTarget,
);
}
/**
* Creates a `Promise` that is fulfilled when the emitter
* emits the given event.
* @param {EventEmitter} emitter
* @param {string} name
* @param {{ signal: AbortSignal; }} [options]
* @returns {Promise}
*/
// deno-lint-ignore require-await
async function once(emitter, name, options = kEmptyObject) {
validateObject(options, "options");
const signal = options?.signal;
validateAbortSignal(signal, "options.signal");
if (signal?.aborted) {
throw new AbortError();
}
if (signal) {
// Patches [kEvents] field of AbortSignal to simulate Node.js EventTarget
// This is necessary to pass `paralle/test-events-once.js` test
// TODO(kt3k): This can be removed if events.getEventListeners() is used
// instead of `signal[kEvents]` in upstream.
ObjectDefineProperty(signal, kEvents, kEventsGetter);
}
return new Promise((resolve, reject) => {
const errorListener = (err) => {
emitter.removeListener(name, resolver);
if (signal != null) {
eventTargetAgnosticRemoveListener(signal, "abort", abortListener);
}
reject(err);
};View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Wrap the await in try/catch and treat code 'ABORT_ERR' as a normal cancellation path (return/ignore), rethrowing everything else
- Check signal?.aborted before calling events.once and skip the wait early
- Use a fresh AbortController per wait, or compose with AbortSignal.any() so unrelated aborts do not leak in
- If aborts are unexpected, find who calls abort() on the shared controller (timeout, shutdown hook, sibling consumer) and scope the signal more narrowly
Example fix
// before
const [msg] = await events.once(emitter, 'ready', { signal: controller.signal });
// after
try {
const [msg] = await events.once(emitter, 'ready', { signal: controller.signal });
} catch (err) {
if (err.code === 'ABORT_ERR') return; // cancelled on purpose
throw err;
} Defensive patterns
Strategy: try-catch
Validate before calling
import events from 'node:events';
function notAborted(signal) {
return !(signal && signal.aborted);
}
if (notAborted(controller.signal)) {
await events.once(emitter, 'ready', { signal: controller.signal });
} Type guard
const isAbortError = (err) => err != null && (err.code === 'ABORT_ERR' || err.name === 'AbortError');
Try / catch
try {
const [value] = await events.once(emitter, name, { signal });
} catch (err) {
if (err.code === 'ABORT_ERR') {
return; // deliberate cancellation: stop cleanly
}
throw err; // real 'error' event or bug: propagate
} Prevention
- Check signal.aborted before every events.once call that takes a signal
- Use one AbortController per logical wait; compose signals with AbortSignal.any() instead of sharing
- Treat ABORT_ERR as a control-flow outcome in design, not an exceptional failure
- Log which path aborted (timeout vs manual) when cancellations are frequent
When it happens
Trigger: Calling events.once(emitter, 'ready', { signal }) with signal.aborted === true; calling controller.abort() (directly or via AbortController.timeout / AbortSignal.timeout) while awaiting events.once; sharing one AbortController across several once() waits so one completion path aborts the others; a shutdown handler aborting a global signal that a pending once() still uses.
Common situations: Implementing request timeouts with AbortController; racing a timeout signal against a server 'ready' event; reusing a signal from an already-cancelled fetch; process-shutdown listeners aborting in-flight waits; version changes where a dependency started passing signals into events.once.
Related errors
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/8bfa242b13db3395.
Report an issue: GitHub.