{"record":{"id":"8bfa242b13db3395","repo":"denoland/deno","slug":"abort-err-8bfa24","errorCode":"ABORT_ERR","errorMessage":"The operation was aborted","messagePattern":"The operation was aborted","errorType":"exception","errorClass":"AbortError","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/_events.mjs","lineNumber":937,"sourceCode":"    emitterOrTarget,\n  );\n}\n\n/**\n * Creates a `Promise` that is fulfilled when the emitter\n * emits the given event.\n * @param {EventEmitter} emitter\n * @param {string} name\n * @param {{ signal: AbortSignal; }} [options]\n * @returns {Promise}\n */\n// deno-lint-ignore require-await\nasync function once(emitter, name, options = kEmptyObject) {\n  validateObject(options, \"options\");\n  const signal = options?.signal;\n  validateAbortSignal(signal, \"options.signal\");\n  if (signal?.aborted) {\n    throw new AbortError();\n  }\n\n  if (signal) {\n    // Patches [kEvents] field of AbortSignal to simulate Node.js EventTarget\n    // This is necessary to pass `paralle/test-events-once.js` test\n    // TODO(kt3k): This can be removed if events.getEventListeners() is used\n    // instead of `signal[kEvents]` in upstream.\n    ObjectDefineProperty(signal, kEvents, kEventsGetter);\n  }\n\n  return new Promise((resolve, reject) => {\n    const errorListener = (err) => {\n      emitter.removeListener(name, resolver);\n      if (signal != null) {\n        eventTargetAgnosticRemoveListener(signal, \"abort\", abortListener);\n      }\n      reject(err);\n    };","sourceCodeStart":919,"sourceCodeEnd":955,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/_events.mjs#L919-L955","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nconst [msg] = await events.once(emitter, 'ready', { signal: controller.signal });\n\n// after\ntry {\n  const [msg] = await events.once(emitter, 'ready', { signal: controller.signal });\n} catch (err) {\n  if (err.code === 'ABORT_ERR') return; // cancelled on purpose\n  throw err;\n}","handlingStrategy":"try-catch","validationCode":"import events from 'node:events';\n\nfunction notAborted(signal) {\n  return !(signal && signal.aborted);\n}\n\nif (notAborted(controller.signal)) {\n  await events.once(emitter, 'ready', { signal: controller.signal });\n}","typeGuard":"const isAbortError = (err) =>\n  err != null &&\n  (err.code === 'ABORT_ERR' || err.name === 'AbortError');","tryCatchPattern":"try {\n  const [value] = await events.once(emitter, name, { signal });\n} catch (err) {\n  if (err.code === 'ABORT_ERR') {\n    return; // deliberate cancellation: stop cleanly\n  }\n  throw err; // real 'error' event or bug: propagate\n}","preventionTips":["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"],"tags":["events","abort-signal","async","node-compat","cancellation"],"backgroundTag":"abort-signal-aborted","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}