{"record":{"id":"e17be4af39f7bef8","repo":"vitest-dev/vitest","slug":"cannot-find-iframe-with-id-event-iframeid","errorCode":null,"errorMessage":"Cannot find iframe with id ${event.iframeId}","messagePattern":"Cannot find iframe with id (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/browser/src/client/orchestrator.ts","lineNumber":486,"sourceCode":"        }\n\n        await client.rpc.onUnhandledError(\n          {\n            name: 'Unexpected Event',\n            message: `Unexpected event: ${(e.data as any).event}`,\n          },\n          'Unexpected Event',\n        )\n      }\n    }\n  }\n\n  private iframeEvents = new WeakMap<HTMLIFrameElement, Set<string>>()\n\n  private async sendEventToIframe(event: IframeChannelOutgoingEvent): Promise<void> {\n    const iframe = this.iframes.get(event.iframeId)\n    if (!iframe) {\n      throw new Error(`Cannot find iframe with id ${event.iframeId}`)\n    }\n    let events = this.iframeEvents.get(iframe)\n    if (!events) {\n      events = new Set()\n      this.iframeEvents.set(iframe, events)\n    }\n    events.add(event.event)\n\n    const messageId = this.messageId++\n    channel.postMessage({ ...event, messageId } satisfies IframeReceivedEvent)\n\n    return new Promise<void>((resolve, reject) => {\n      let ackTimer: ReturnType<typeof setTimeout>\n\n      const cleanupEvents = () => {\n        clearTimeout(ackTimer)\n        channel.removeEventListener('message', onReceived)\n        this.eventTarget.removeEventListener('iframeerror', onError)","sourceCodeStart":468,"sourceCodeEnd":504,"githubUrl":"https://github.com/vitest-dev/vitest/blob/1fa9837ec26533512fdcad8baebf249771bd340a/packages/browser/src/client/orchestrator.ts#L468-L504","documentation":"The browser orchestrator multiplexes tests across iframes keyed by iframeId. sendEventToIframe looks up the iframe in this.iframes; if it was removed (removeIframe deletes the entry) or never registered, it throws. Messages are dispatched to tester iframes during normal test execution (prepare, run, collect).","triggerScenarios":"The orchestrator tries to send an event (prepare/run/etc.) to an iframe that has been removed (tester crashed, reloaded, or was torn down) or whose id was never registered (typo, race during registration). Common when an iframe reloads mid-test and is removed before a queued message is dispatched.","commonSituations":"Iframe navigated/reloaded during a test (e.g., form submit without preventDefault, router location change) triggering removal; tester crash; timing race where an event is queued before the iframe's onload registers it.","solutions":["Avoid navigating/reloading the iframe from test code: call `event.preventDefault()` on form submits and use memory-based routing for SPA routers.","Ensure dependencies are optimized (configure `optimizeDeps`) so the tester iframe does not reload.","If seen sporadically in CI, check for tester crashes/unhandled errors that remove the iframe.","Report persistent occurrences with a reproduction — this often indicates a race the orchestrator should tolerate."],"exampleFix":"// before\nform.dispatchEvent(new Event('submit')) // browser reloads iframe -> orchestrator removes it\n\n// after\nform.addEventListener('submit', (e) => e.preventDefault())\nform.dispatchEvent(new Event('submit'))","handlingStrategy":"try-catch","validationCode":"// there is no public pre-check; reduce likelihood by avoiding iframe reloads:\nform.addEventListener('submit', (e) => e.preventDefault())\nawait expect(page.getByRole('button')).toBeVisible() // wait for tester readiness","typeGuard":null,"tryCatchPattern":"// orchestrator-internal; if surfacing in custom UI integration:\ntry {\n  await sendEventToIframe(event)\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith('Cannot find iframe')) {\n    // iframe was removed; re-register or skip this event\n    return\n  }\n  throw err\n}","preventionTips":["Prevent iframe navigation/reload in tests (preventDefault on submit, memory routing).","Ensure optimizeDeps includes all deps so the tester does not reload.","Handle tester errors promptly so the orchestrator does not target a removed iframe."],"tags":["browser","orchestrator","iframe","race-condition","ui-mode"],"backgroundTag":null,"analyzedSha":"1fa9837ec26533512fdcad8baebf249771bd340a","analyzedAt":"2026-08-11T16:11:39.638Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}