{"record":{"id":"59fa9311ef5c7838","repo":"musistudio/claude-code-router","slug":"qr-window-sessionid-is-required","errorCode":null,"errorMessage":"QR window sessionId is required.","messagePattern":"QR window sessionId is required\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/electron/src/main/bot-gateway-qr-window-service.ts","lineNumber":16,"sourceCode":"import { BrowserWindow, shell } from \"electron\";\nimport type {\n  BotGatewayQrWindowCloseRequest,\n  BotGatewayQrWindowCloseResult,\n  BotGatewayQrWindowOpenRequest,\n  BotGatewayQrWindowOpenResult\n} from \"@ccr/core/contracts/app\";\n\nconst qrWindows = new Map<string, BrowserWindow>();\n\nexport async function openBotGatewayQrWindow(\n  request: BotGatewayQrWindowOpenRequest\n): Promise<BotGatewayQrWindowOpenResult> {\n  const sessionId = request.sessionId.trim();\n  if (!sessionId) {\n    throw new Error(\"QR window sessionId is required.\");\n  }\n\n  const url = parseQrWindowUrl(request.url);\n  const existing = qrWindows.get(sessionId);\n  if (existing && !existing.isDestroyed()) {\n    if (existing.webContents.getURL() !== url) {\n      await loadQrWindowUrl(existing, url, Boolean(request.waitForScan));\n    }\n    existing.show();\n    existing.focus();\n    if (request.waitForScan) {\n      return { opened: true, ...await waitForQrWindowClose(existing) };\n    }\n    return { opened: true };\n  }\n\n  const window = new BrowserWindow({\n    height: 760,","sourceCodeStart":1,"sourceCodeEnd":34,"githubUrl":"https://github.com/musistudio/claude-code-router/blob/99f24806c6a2c660b16e53e95211c517448a6c90/packages/electron/src/main/bot-gateway-qr-window-service.ts#L1-L34","documentation":"Thrown by openBotGatewayQrWindow when the sessionId in the open request is empty after trimming. The Electron main process uses sessionId to key QR login windows so repeated opens for the same session reuse the existing window; without it the window cannot be tracked or deduplicated.","triggerScenarios":"Calling openBotGatewayQrWindow({ sessionId: \"\" }) or with a whitespace-only sessionId, or destructuring a request object whose sessionId field was never populated.","commonSituations":"The session was created upstream but its id wasn't propagated into the QR window request; a caller passes a placeholder empty string while bootstrapping.","solutions":["Pass the real session identifier from the bot gateway session that owns the QR login flow.","Validate/trim the sessionId before calling openBotGatewayQrWindow and surface a form error to the user if empty."],"exampleFix":"// before\nawait openBotGatewayQrWindow({ sessionId: \"  \", url });\n\n// after\nconst sessionId = session.id.trim();\nif (sessionId) await openBotGatewayQrWindow({ sessionId, url });","handlingStrategy":"validation","validationCode":"const sessionId = request.sessionId?.trim();\nif (!sessionId) { /* show user-facing error */ } else { await openBotGatewayQrWindow({ ...request, sessionId }); }","typeGuard":"function hasSessionId(r: unknown): r is BotGatewayQrWindowOpenRequest { return typeof (r as any)?.sessionId === \"string\" && (r as any).sessionId.trim().length > 0; }","tryCatchPattern":"try { await openBotGatewayQrWindow(req); } catch (e) { if (e instanceof Error && e.message.includes(\"sessionId is required\")) return { error: \"Session id missing\" }; throw e; }","preventionTips":["Propagate session.id from session creation into every QR window call","Trim ids at the boundary","Fail fast in UI when session bootstrap hasn't produced an id"],"tags":["validation","required-field","qr-window","electron"],"backgroundTag":"missing-required-field","analyzedSha":"99f24806c6a2c660b16e53e95211c517448a6c90","analyzedAt":"2026-08-27T04:11:01.184Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}