can1357/oh-my-pi · error · Error
error
Error message
error
What it means
formatCollabLink normalizes the relay URL before rendering the shareable link and throws when normalizeRelayOrigin returns an error — an unparseable URL, an unsupported scheme, or ws:// pointing at a non-localhost host. This is the same relay-URL validation as the host-start path, surfaced at link formatting time.
Source
Thrown at packages/coding-agent/src/collab/protocol.ts:197
/**
* Render the shareable link. Compact forms: the default relay collapses to
* `<roomId>.<key>`, other wss relays drop the scheme (`host[:port]/r/…`);
* only localhost ws:// links keep their full URL so parsing cannot
* mis-infer wss.
*
* The room secret is dot-joined (`<roomId>.<key>`) rather than `#`-joined:
* RFC 3986 forbids a raw `#` inside a fragment, so strict URL stacks (macOS
* Foundation behind terminal click-to-open) percent-encode a second `#` to
* `%23` and break the link. Parsers still accept the legacy `#` form and the
* mangled `%23` form.
*
* Full links append the write token to the key
* (`base64url(key ∥ writeToken)`); read-only (view) links carry the bare
* 32-byte key, which is also the pre-token link format.
*/
export function formatCollabLink(relayUrl: string, roomId: string, key: Uint8Array, writeToken?: Uint8Array): string {
const normalized = normalizeRelayOrigin(relayUrl);
if ("error" in normalized) throw new Error(normalized.error);
const secret = writeToken ? Buffer.concat([key, writeToken]) : Buffer.from(key);
const keyText = secret.toString("base64url");
if (normalized.origin === DEFAULT_RELAY_URL) return `${roomId}.${keyText}`;
const compact = normalized.origin.startsWith("wss://")
? normalized.origin.slice("wss://".length)
: normalized.origin;
return `${compact}/r/${roomId}.${keyText}`;
}
function normalizeCollabWebBaseUrl(relayUrl: string, webUrl?: string): string {
const explicitWebUrl = webUrl?.trim();
if (!explicitWebUrl) {
const normalized = normalizeRelayOrigin(relayUrl);
if ("error" in normalized) throw new Error(normalized.error);
return normalized.origin.startsWith("wss://")
? `https://${normalized.origin.slice("wss://".length)}`
: `http://${normalized.origin.slice("ws://".length)}`;
}View on GitHub (pinned to 9690622007)
Solutions
- Pass a complete ws:// or wss:// URL with hostname (and optional port) as relayUrl.
- For remote relays use wss://; reserve ws:// for localhost/127.0.0.1/::1 only.
- Validate with new URL(relayUrl) and check url.protocol in ["ws:","wss:","http:","https:"] before calling.
- Use the DEFAULT_RELAY_URL (empty relayUrl handling in the caller) if self-hosting is not intended.
Example fix
// before
formatCollabLink("ws://relay.example.com", roomId, key); // plain ws off localhost
// after
formatCollabLink("wss://relay.example.com", roomId, key); Defensive patterns
Strategy: validation
Validate before calling
const u = new URL(relayUrl); // throws if invalid
const schemeOk = ["ws:", "wss:", "http:", "https:"].includes(u.protocol);
const localOk = u.protocol !== "ws:" || ["localhost", "127.0.0.1", "::1"].includes(u.hostname);
if (!schemeOk || !localOk) throw new Error(`unsupported relayUrl: ${relayUrl}`);
formatCollabLink(relayUrl, roomId, key, token); Try / catch
try {
const link = formatCollabLink(relayUrl, roomId, key, token);
} catch (err) {
ui.showError(`Cannot format link: ${(err as Error).message}`);
} Prevention
- Normalize relay URLs (scheme + host + optional port) at the edge of your app once, then reuse.
- Prefer the default relay (omit/empty relayUrl) unless self-hosting deliberately.
- Add a config-load-time check that relayUrl parses with an allowed scheme.
When it happens
Trigger: Calling formatCollabLink(relayUrl, roomId, key[, writeToken]) with relayUrl that is not a valid absolute URL, has a scheme other than ws/wss/http/https, or uses ws:// with a non-local hostname. Also reachable via formatCollabWebLink, which calls it after building the web base URL.
Common situations: Environment/config variable for the relay is empty or a bare hostname; a self-hosted relay configured as 'http://relay:8080' works, but 'ftp://relay' or a typo ('wss//relay') fails; ws:// used for a remote relay in a dev environment with a real hostname.
Related errors
- error
- collab.webUrl must start with http:// or https://
- resultBaseUrl is not a valid URL
- Destination option ${optionName} must use http or https
- collab.webUrl must use https:// unless it targets localhost
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/e554a89bdb09085c.
Report an issue: GitHub.