can1357/oh-my-pi · error · Error
error
Error message
error
What it means
CollabGuest.join parses a collaboration invite link before connecting. parseCollabLink returns a discriminated result; when it carries an "error" field, join converts it into a thrown Error with the parser's message (e.g. 'Invalid collab link: ...', 'Collab link must contain a /r/<roomId> path', 'Collab link key must be 32 (view) or 48 (full) base64url bytes'). The join is aborted because no room can be addressed without a valid roomId/wsUrl/key.
Source
Thrown at packages/coding-agent/src/collab/guest.ts:256
/** True when this guest joined through a read-only (view) link. */
get readOnly(): boolean {
return this.#readOnly;
}
/** Shows the read-only status hint when applicable; true when the action must be dropped. */
#rejectReadOnly(): boolean {
if (!this.#readOnly) return false;
this.#ctx.showStatus("This collab link is read-only");
return true;
}
constructor(ctx: InteractiveModeContext) {
this.#ctx = ctx;
}
async join(link: string): Promise<void> {
const parsed = parseCollabLink(link);
if ("error" in parsed) throw new Error(parsed.error);
this.#roomId = parsed.roomId;
this.#writeToken = parsed.writeToken ? Buffer.from(parsed.writeToken).toString("base64url") : undefined;
const key = await importRoomKey(parsed.key);
this.#returnSessionFile = this.#ctx.sessionManager.getSessionFile() ?? null;
const socket = new CollabSocket({ wsUrl: parsed.wsUrl, role: "guest", key });
this.#socket = socket;
const firstWelcome = Promise.withResolvers<void>();
let joined = false;
this.#joinReject = err => firstWelcome.reject(err);
const finishJoin = (): void => {
if (joined) return;
joined = true;
firstWelcome.resolve();
};View on GitHub (pinned to 9690622007)
Solutions
- Re-copy the complete invite link from the host's output — verify it ends with a long base64url key segment after the roomId.
- If the link came from a chat/terminal that mangled it (e.g. %23, line breaks), strip whitespace and replace %23 with #, or use the bare roomId.key form.
- Run parseCollabLink(link) first and surface its error to the user instead of a raw throw.
- Use the web deep link variant if the plain link keeps getting corrupted by click-to-open.
Example fix
// before
await guest.join(userInput); // throws opaque parsed.error
// after
const parsed = parseCollabLink(userInput);
if ("error" in parsed) {
ui.showError("Invalid collaboration link: " + parsed.error);
return;
}
await guest.join(userInput); Defensive patterns
Strategy: try-catch
Validate before calling
const parsed = parseCollabLink(link);
if ("error" in parsed) {
report(`Invalid link: ${parsed.error}`);
return;
} Type guard
function isParsedCollabLink(p: ReturnType<typeof parseCollabLink>): p is ParsedCollabLink {
return !("error" in p);
} Try / catch
try {
await guest.join(link);
} catch (err) {
ui.showError(`Join failed: ${err instanceof Error ? err.message : String(err)}`);
} Prevention
- Copy the full link in one action; avoid terminals/chat clients that wrap or rewrite it.
- Sanitize pasted input: trim whitespace, restore %23 to #.
- Prefer sharing web deep links which survive strict URL stacks.
When it happens
Trigger: Calling guest.join(link) with: a link whose key fragment is not valid base64url or is not 32/48 bytes; a URL missing the /r/<roomId> path; an unparseable URL string; a relay origin with an unsupported scheme (e.g. ftp://); an empty or whitespace link.
Common situations: The user pasted a partial link (key cut off by line-wrap when copying from a terminal); the link went through a chat client that percent-encoded or stripped characters; a user typed a room name instead of a full link; sharing a web deep-link fragment without the surrounding http(s) URL.
Related errors
- err.to_string() (timestamp parse error)
- duration is too large: {value}
- invalid date: {value}
- date is out of range
- dates before 1970 are unsupported
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/c4671efd975df2fb.
Report an issue: GitHub.