{"record":{"id":"1bf6a99ffd6604b1","repo":"denoland/deno","slug":"invalidstateerror-1bf6a9","errorCode":"InvalidStateError","errorMessage":"Invalid event state","messagePattern":"Invalid event state","errorType":"exception","errorClass":"DOMException","httpStatus":null,"severity":"error","filePath":"ext/web/02_event.js","lineNumber":1127,"sourceCode":"    );\n\n    // This is an optimization to avoid creating an event listener\n    // on each startup.\n    // Stores the flag for checking whether unload is dispatched or not.\n    // This prevents the recursive dispatches of unload events.\n    // See https://github.com/denoland/deno/issues/9201.\n    if (event.type === \"unload\" && self === globalThis_) {\n      globalThis_[SymbolFor(\"Deno.isUnloadDispatched\")] = true;\n    }\n\n    const data = self[eventTargetData];\n    if (data === undefined || !data.listeners[event.type]) {\n      setTarget(event, this);\n      return true;\n    }\n\n    if (getDispatched(event)) {\n      throw new DOMException(\"Invalid event state\", \"InvalidStateError\");\n    }\n\n    if (event.eventPhase !== Event.NONE) {\n      throw new DOMException(\"Invalid event state\", \"InvalidStateError\");\n    }\n\n    return dispatch(self, event);\n  }\n\n  getParent(_event) {\n    return null;\n  }\n\n  [SymbolFor(\"Deno.privateCustomInspect\")](inspect, inspectOptions) {\n    return `${this.constructor.name} ${inspect({}, inspectOptions)}`;\n  }\n}\n","sourceCodeStart":1109,"sourceCodeEnd":1145,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/web/02_event.js#L1109-L1145","documentation":"EventTarget.prototype.dispatchEvent throws DOMException 'Invalid event state' (InvalidStateError) when the event's internal [[dispatched]] flag is set — i.e. the same Event object is dispatched again while still inside dispatch() (checked at ext/web/02_event.js:1126). In Deno's implementation the flag is set on entry to dispatch() (ext/web/02_event.js:571) and cleared only when the dispatch completes normally (ext/web/02_event.js:711), so it fires for synchronous re-dispatch from within one of the event's own listeners, and also when a listener threw during an earlier dispatch of the same object and left the flag permanently set. This matches the DOM spec rule that an event must never be dispatched while its dispatch flag is active.","triggerScenarios":"bus.addEventListener('ping', (e) => hub.dispatchEvent(e)); bus.dispatchEvent(new Event('ping')); — the live event object is re-dispatched synchronously inside its own listener. Also: a listener threw during the first dispatch (the reset at ext/web/02_event.js:708-713 never ran), so every later dispatchEvent(sameEvent) throws InvalidStateError forever.","commonSituations":"Middleware/event-bus designs that forward the live event object to a central EventTarget synchronously; fan-out code that re-dispatches a captured event; test harnesses reusing one Event instance across listeners; migrating from Node EventEmitter where emit is freely re-callable.","solutions":["Do not re-dispatch the event object itself; forward its payload to a fresh event: hub.dispatchEvent(new CustomEvent(e.type, { detail: e.detail })).","Defer the second dispatch with queueMicrotask() so the first dispatch finishes and clears the flag first.","If the error appears on a later dispatch after a listener threw, the event object is poisoned — create a new Event every time.","Audit addEventListener callbacks for dispatchEvent calls that pass through their own event argument."],"exampleFix":"// before\nbus.addEventListener('ping', (e) => hub.dispatchEvent(e)); // e is mid-dispatch -> Invalid event state\nbus.dispatchEvent(new Event('ping'));\n\n// after\nbus.addEventListener('ping', (e) =>\n  hub.dispatchEvent(new CustomEvent(e.type, { detail: e.detail }))\n);","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  target.dispatchEvent(evt);\n} catch (e) {\n  if (e instanceof DOMException && e.name === 'InvalidStateError') {\n    target.dispatchEvent(new Event(evt.type, { bubbles: evt.bubbles, cancelable: evt.cancelable }));\n  } else throw e;\n}","preventionTips":["Construct a new Event at each dispatch site","Never cache Event instances in module or class scope","Forward event payload (type/detail), not the live event object","If a listener threw during dispatch, discard that event object"],"tags":["event","eventtarget","dispatchevent","dom"],"backgroundTag":"event-reentrant-dispatch","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}