{"record":{"id":"661962c5cb8463f0","repo":"microsoft/playwright","slug":"unknown-stream-params-streamid","errorCode":null,"errorMessage":"Unknown stream: ${params.streamId}","messagePattern":"Unknown stream: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/playwright-core/src/tools/dashboard/dashboardController.ts","lineNumber":259,"sourceCode":"\n  async reveal(params: { path: string }) {\n    switch (os.platform()) {\n      case 'darwin':\n        execFile('open', ['-R', params.path]);\n        break;\n      case 'win32':\n        execFile('explorer', ['/select,', params.path]);\n        break;\n      case 'linux':\n        execFile('xdg-open', [path.dirname(params.path)]);\n        break;\n    }\n  }\n\n  async readStream(params: { streamId: string }): Promise<{ data: string; eof: boolean }> {\n    const stream = this._streams.get(params.streamId);\n    if (!stream)\n      throw new Error(`Unknown stream: ${params.streamId}`);\n    const buffer = Buffer.alloc(256 * 1024);\n    const { bytesRead } = await stream.handle.read(buffer, 0, buffer.length);\n    if (bytesRead === 0) {\n      this._streams.delete(params.streamId);\n      await stream.handle.close().catch(() => {});\n      await fs.promises.unlink(stream.path).catch(() => {});\n      return { data: '', eof: true };\n    }\n    return { data: buffer.subarray(0, bytesRead).toString('base64'), eof: false };\n  }\n\n  visible(): boolean {\n    return this._visible;\n  }\n\n  emitSessions(sessions: BrowserDescriptor[]) {\n    this.sendEvent?.('sessions', { sessions, clientInfo: createClientInfo() });\n  }","sourceCodeStart":241,"sourceCodeEnd":277,"githubUrl":"https://github.com/microsoft/playwright/blob/c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6/packages/playwright-core/src/tools/dashboard/dashboardController.ts#L241-L277","documentation":"Thrown by the dashboard controller's `readStream` when `params.streamId` is not present in `_streams`. Streams are registered when produced (e.g. by `stopRecording`) and removed once EOF is returned or the handle is closed, so a second read after EOF, a stale id, or an invalid id all miss the map.","triggerScenarios":"Calling `readStream` with a `streamId` that was already consumed to EOF (the read that returns `eof:true` also deletes the entry), with a typo'd/foreign id, or before any stream was opened.","commonSituations":"Dashboard UI re-requests a recording after the download completed; a reconnecting dashboard client replaying an old stream id; concurrent reads racing past EOF.","solutions":["Stop reading a stream once you receive `eof: true` — that response consumes the entry.","Track the lifecycle of stream ids client-side and discard them on EOF.","If the id came from `stopRecording`, ensure you only read it once per recording."],"exampleFix":"// before\nlet { data, eof } = await controller.readStream({ streamId });\n// ... later, reuse same streamId ...\nawait controller.readStream({ streamId }); // throws\n// after\nlet eof = false;\nwhile (!eof) {\n  const r = await controller.readStream({ streamId });\n  data += r.data; eof = r.eof;\n}\n// do not reuse streamId after the loop","handlingStrategy":"validation","validationCode":"// Track consumed streams client-side.\nconst consumed = new Set<string>();\nasync function readFully(streamId: string) {\n  if (consumed.has(streamId)) throw new Error(`stream already consumed: ${streamId}`);\n  let data = '', eof = false;\n  while (!eof) {\n    const r = await controller.readStream({ streamId });\n    data += r.data; eof = r.eof;\n  }\n  consumed.add(streamId);\n  return data;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never call readStream after receiving eof:true (that entry is gone).","Discard stream ids client-side once consumed.","Bind each read sequence to a single stream id obtained from stopRecording."],"tags":["dashboard","stream","lifecycle","recording"],"backgroundTag":null,"analyzedSha":"c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6","analyzedAt":"2026-08-12T07:26:36.950Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}