{"record":{"id":"9a6c8ffbd729d24a","repo":"denoland/deno","slug":"err-event-recursion","errorCode":"ERR_EVENT_RECURSION","errorMessage":"The event \"${event.type}\" is already being dispatched","messagePattern":"The event \"(.+?)\" is already being dispatched","errorType":"exception","errorClass":"NodeError","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/internal/event_target.mjs","lineNumber":708,"sourceCode":"      }\n      handler = handler.next;\n    }\n  }\n\n  /**\n   * @param {Event} event\n   */\n  dispatchEvent(event) {\n    if (!isEventTarget(this)) {\n      throw new ERR_INVALID_THIS(\"EventTarget\");\n    }\n\n    if (!ObjectPrototypeIsPrototypeOf(globalThis.Event.prototype, event)) {\n      throw new ERR_INVALID_ARG_TYPE(\"event\", \"Event\", event);\n    }\n\n    if (event[kIsBeingDispatched]) {\n      throw new ERR_EVENT_RECURSION(event.type);\n    }\n\n    this[kHybridDispatch](event, event.type, event);\n\n    return event.defaultPrevented !== true;\n  }\n\n  [kHybridDispatch](nodeValue, type, event) {\n    const createEvent = () => {\n      if (event === undefined) {\n        event = this[kCreateEvent](nodeValue, type);\n        event[kTarget] = this;\n        event[kIsBeingDispatched] = true;\n      }\n      return event;\n    };\n    if (event !== undefined) {\n      event[kTarget] = this;","sourceCodeStart":690,"sourceCodeEnd":726,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/internal/event_target.mjs#L690-L726","documentation":"Node keeps a [kIsBeingDispatched] flag on each event; dispatchEvent refuses any event whose flag is still set, throwing ERR_EVENT_RECURSION. This happens when the exact same Event instance is re-dispatched synchronously while its own listeners are still running. Dispatching a fresh event with the same type is always legal.","triggerScenarios":"Inside a listener for event e, calling target.dispatchEvent(e) with the same object; replay utilities that cache the last real event and re-dispatch the cached instance; retry logic inside a listener that re-fires the triggering event; forwarding pipelines that pass the received event object to another dispatchEvent call.","commonSituations":"Event-replay and mocking helpers that store live events; middleware that wraps dispatchEvent and re-dispatches the same instance; one CustomEvent object hoisted to module scope and reused for every emit.","solutions":["Dispatch a fresh instance: dispatchEvent(new Event(e.type)) instead of e","For CustomEvent payloads: dispatchEvent(new CustomEvent(e.type, { detail: e.detail }))","If re-dispatch must happen in the listener, defer it: queueMicrotask(() => target.dispatchEvent(new Event(e.type)))","Audit listeners that forward the event they received into another dispatchEvent"],"exampleFix":"// before\ntarget.addEventListener('tick', (e) => {\n  target.dispatchEvent(e); // same instance, still dispatching\n});\n\n// after\ntarget.addEventListener('tick', (e) => {\n  target.dispatchEvent(new CustomEvent(e.type, { detail: e.detail }));\n});","handlingStrategy":"validation","validationCode":"function safeDispatch(target, type, detail) {\n  // always build a fresh event: a cached/in-flight instance would throw ERR_EVENT_RECURSION\n  const ev = detail === undefined ? new Event(type) : new CustomEvent(type, { detail });\n  target.dispatchEvent(ev);\n}","typeGuard":null,"tryCatchPattern":"try { target.dispatchEvent(e); } catch (err) { if (err?.code === 'ERR_EVENT_RECURSION') { queueMicrotask(() => target.dispatchEvent(new Event(e.type))); return; } throw err; }","preventionTips":["Never reuse an Event instance across dispatches; treat events as single-shot","In listeners that re-fire, construct a new event with the same type and copied detail","Defer re-dispatch with queueMicrotask/setTimeout if ordering matters"],"tags":["event-target","recursion","dispatch","node-compat","deno"],"backgroundTag":"event-recursion","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}