{"id":"668114d48c1bfa6f","repo":"vitest-dev/vitest","slug":"tester-rpc-rpcid-was-not-established","errorCode":null,"errorMessage":"Tester RPC \"${rpcId}\" was not established.","messagePattern":"Tester RPC \"(.+?)\" was not established\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/browser/src/node/projectParent.ts","lineNumber":221,"sourceCode":"    const provider = browser.provider\n    if (!provider) {\n      throw new Error(`Browser provider is not defined for the project \"${browserSession.project.name}\".`)\n    }\n    if (!provider.getCDPSession) {\n      throw new Error(`CDP is not supported by the provider \"${provider.name}\".`)\n    }\n\n    const session = await this.cdpSessionsPromises.get(rpcId) ?? await (async () => {\n      const promise = provider.getCDPSession!(sessionId).finally(() => {\n        this.cdpSessionsPromises.delete(rpcId)\n      })\n      this.cdpSessionsPromises.set(rpcId, promise)\n      return promise\n    })()\n\n    const rpc = (browser.state as BrowserServerState).testers.get(rpcId)\n    if (!rpc) {\n      throw new Error(`Tester RPC \"${rpcId}\" was not established.`)\n    }\n\n    const handler = new BrowserServerCDPHandler(session, rpc)\n    this.cdps.set(\n      rpcId,\n      handler,\n    )\n    return handler\n  }\n\n  removeCDPHandler(sessionId: string): void {\n    this.cdps.delete(sessionId)\n  }\n\n  async formatScripts(scripts: BrowserScript[] | undefined): Promise<HtmlTagDescriptor[]> {\n    if (!scripts?.length) {\n      return []\n    }","sourceCodeStart":203,"sourceCodeEnd":239,"githubUrl":"https://github.com/vitest-dev/vitest/blob/d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09/packages/browser/src/node/projectParent.ts#L203-L239","documentation":"After obtaining a CDP session, `ensureCDPHandler` looks up the tester RPC channel by `rpcId` in `browser.state.testers`. The tester RPC is registered when the tester websocket connects (type='tester' in the upgrade handler). If no tester is registered for that rpcId, the CDP handler has nowhere to forward events.","triggerScenarios":"Requesting a CDP handler for an `rpcId` whose tester websocket never connected, or already disconnected (the `close` handler deletes it).","commonSituations":"CDP call before the tester iframe finished connecting; tester tab crashed/closed between the CDP request and handler creation; rpcId mismatch between orchestrator and tester connections.","solutions":["Ensure the tester page is open and connected before issuing CDP calls.","Verify the rpcId passed to `ensureCDPHandler` matches the one used by the tester websocket.","Retry after a short delay if the tester is still loading — but prefer waiting for an explicit ready signal."],"exampleFix":"// before — CDP call before tester connected\nawait sendCdpEvent(sessionId, 'Page.reload')\n\n// after — wait for tester ready\nawait page.waitForLoadState?.() // or your framework's ready hook\nawait sendCdpEvent(sessionId, 'Page.reload')","handlingStrategy":"validation","validationCode":"function testerRpcReady(state: { testers: Map<string, unknown> }, rpcId: string): boolean {\n  return state.testers.has(rpcId)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Issue CDP calls only after the tester page is connected (e.g. via the ready event).","Verify the rpcId matches the tester websocket's id.","Avoid CDP calls during teardown — the tester may have already disconnected."],"tags":["cdp","rpc","tester","session"],"analyzedSha":"d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09","analyzedAt":"2026-08-03T20:23:56.861Z","schemaVersion":2}