{"record":{"id":"2d4f214541244ff7","repo":"can1357/oh-my-pi","slug":"parsed-error","errorCode":null,"errorMessage":"${parsed.error}","messagePattern":"\\$\\{parsed\\.error\\}","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/collab-web/src/lib/client.ts","lineNumber":126,"sourceCode":"\t#entries: readonly SessionEntry[] = [];\n\t#state: SessionState | null = null;\n\t#agents: readonly AgentSnapshot[] = [];\n\t#progress: ReadonlyMap<string, SubagentProgressPayload> = new Map();\n\t#lifecycle: ReadonlyMap<string, SubagentLifecyclePayload> = new Map();\n\t#stream: AssistantMessage | null = null;\n\t#streamDone = false;\n\t#activeTools: ReadonlyMap<string, ActiveTool> = new Map();\n\t#working = false;\n\t#readOnly = false;\n\t#uiRequest: CollabUiRequest | null = null;\n\t#uiRequestQueue: CollabUiRequest[] = [];\n\t#notices: readonly Notice[] = [];\n\t#snapshot: GuestSnapshot;\n\n\t/** @throws Error when the link does not parse. */\n\tconstructor(link: string, displayName: string) {\n\t\tconst parsed = parseCollabLink(link);\n\t\tif (\"error\" in parsed) throw new Error(parsed.error);\n\t\tthis.#name = displayName;\n\t\tthis.#writeToken = parsed.writeToken ? encodeBase64Url(parsed.writeToken) : undefined;\n\t\tthis.#socket = new CollabSocket({ wsUrl: parsed.wsUrl, role: \"guest\", key: importRoomKey(parsed.key) });\n\t\tthis.#socket.onOpen = () => this.#handleOpen();\n\t\tthis.#socket.onFrame = frame => this.#applyFrameSafe(frame);\n\t\tthis.#socket.onControl = msg => {\n\t\t\tif (msg.t === \"room-closed\") this.#end(\"room closed\");\n\t\t};\n\t\tthis.#socket.onClose = (reason, willReconnect) => this.#handleClose(reason, willReconnect);\n\t\tthis.#snapshot = this.#buildSnapshot();\n\t}\n\n\tconnect(): void {\n\t\tif (this.#phase === \"ended\") {\n\t\t\tthis.#phase = \"connecting\";\n\t\t\tthis.#endedReason = null;\n\t\t\tthis.#commit();\n\t\t}","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/collab-web/src/lib/client.ts#L108-L144","documentation":"The CollabGuest constructor parses a collaboration invite link via parseCollabLink; if the link is malformed the parser returns an error object and the constructor throws a plain Error with the parser's message. Since constructors throw, an invalid link can never produce a guest instance.","triggerScenarios":"Constructing CollabGuest (or the guest client) with a collab link string that fails parsing: wrong base64url key segment, missing roomId, bad relay URL, truncated or hand-edited link.","commonSituations":"Users copy-pasting invite URLs and truncating them, chat apps wrapping URLs and breaking them, manually constructing links with wrong encoding, or links from an older relay format.","solutions":["Re-copy the full invite link from the source without truncation","Validate the link with parseCollabLink before constructing and show a user-friendly message on error","Ensure the link was generated by formatCollabLink on the host side with matching relay format","Check for a version mismatch between the link generator and client codec formats"],"exampleFix":"// before\nconst guest = new CollabGuest(link, name); // throws on bad link\n// after\nconst parsed = parseCollabLink(link);\nif (!(\"error\" in parsed)) {\n  const guest = new CollabGuest(link, name);\n} else {\n  showError(\"Invalid collaboration link: \" + parsed.error);\n}","handlingStrategy":"validation","validationCode":"const parsed = parseCollabLink(link);\nif (\"error\" in parsed) {\n  throw new Error(\"Invalid collaboration link: \" + parsed.error);\n}","typeGuard":"function isValidCollabLink(\n  parsed: ReturnType<typeof parseCollabLink>,\n): parsed is Exclude<ReturnType<typeof parseCollabLink>, { error: string }> {\n  return !(\"error\" in parsed);\n}","tryCatchPattern":"try {\n  const guest = new CollabGuest(link, displayName);\n} catch (e) {\n  showUserError(\"This invite link is invalid or incomplete. Please re-copy the full link.\");\n}","preventionTips":["Never truncate invite links when sharing (use dedicated share buttons, not manual copy)","Validate with parseCollabLink before constructing the client","Regenerate links from the host if joining fails repeatedly","Check both host and guest use the same library version/link format"],"tags":["collaboration","parsing","validation"],"backgroundTag":"invalid-invite-link","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}