can1357/oh-my-pi · error · ToolError

Invalid cmux relay auth metadata in ~/.cmux/relay/${endpoint

Error message

Invalid cmux relay auth metadata in ~/.cmux/relay/${endpoint.port}.auth

What it means

The relay auth file ~/.cmux/relay/<port>.auth was readable and valid JSON, but its relay_id/relay_token fields failed parseRelayCredentials: both must be non-empty strings and the token must be an even-length hex string. The client refuses to attempt HMAC auth with malformed credentials.

Source

Thrown at packages/coding-agent/src/tools/browser/cmux/socket-client.ts:212

		if (environmentCredentials) {
			return environmentCredentials;
		}

		const authPath = path.join(os.homedir(), ".cmux", "relay", `${endpoint.port}.auth`);
		let payload: unknown;
		try {
			payload = await Bun.file(authPath).json();
		} catch {
			throw new ToolError(
				`Missing cmux relay auth metadata for ${endpoint.host}:${endpoint.port}; set CMUX_RELAY_ID/CMUX_RELAY_TOKEN or restore ~/.cmux/relay/${endpoint.port}.auth`,
			);
		}
		const relayId = payload && typeof payload === "object" && "relay_id" in payload ? payload.relay_id : undefined;
		const relayToken =
			payload && typeof payload === "object" && "relay_token" in payload ? payload.relay_token : undefined;
		const fileCredentials = parseRelayCredentials(relayId, relayToken);
		if (!fileCredentials) {
			throw new ToolError(`Invalid cmux relay auth metadata in ~/.cmux/relay/${endpoint.port}.auth`);
		}
		return fileCredentials;
	}

	async #authenticateRelay(endpoint: RelayEndpoint, credentials: RelayCredentials): Promise<void> {
		const challengeLine = await this.#nextLine(DEFAULT_CONNECT_TIMEOUT_MS);
		let challenge: unknown;
		try {
			challenge = JSON.parse(challengeLine);
		} catch {
			throw new ToolError(`Invalid cmux relay authentication challenge from ${endpoint.host}:${endpoint.port}`);
		}
		if (
			!challenge ||
			typeof challenge !== "object" ||
			!("protocol" in challenge) ||
			challenge.protocol !== "cmux-relay-auth" ||
			!("version" in challenge) ||

View on GitHub (pinned to 9690622007)

Solutions

  1. Fix the .auth file so relay_id is a non-empty string and relay_token is a non-empty even-length hex string
  2. Prefer setting CMUX_RELAY_ID/CMUX_RELAY_TOKEN env vars instead — env credentials take precedence over the file
  3. Regenerate the file from cmux rather than hand-editing it

Example fix

// before (~/.cmux/relay/8931.auth)
{ "relay_id": "relay-abc", "relay_token": "c28tZS10b2tlbg==" }
// after (token as hex)
{ "relay_id": "relay-abc", "relay_token": "736f6d652d746f6b656e" }
Defensive patterns

Strategy: validation

Validate before calling

const auth = JSON.parse(await Bun.file(authPath).text());
const ok = typeof auth.relay_id === 'string' && auth.relay_id.length > 0 &&
  typeof auth.relay_token === 'string' && /^[0-9a-f]+$/.test(auth.relay_token) &&
  auth.relay_token.length % 2 === 0;
if (!ok) throw new Error('malformed relay auth file — regenerate from cmux');

Type guard

function isRelayAuthPayload(v: unknown): v is { relay_id: string; relay_token: string } {
  if (typeof v !== 'object' || v === null) return false;
  const o = v as Record<string, unknown>;
  return typeof o.relay_id === 'string' && o.relay_id.length > 0 &&
    typeof o.relay_token === 'string' && o.relay_token.length > 0 &&
    o.relay_token.length % 2 === 0 && /^[0-9a-f]+$/i.test(o.relay_token);
}

Try / catch

try {
  await client.connect();
} catch (err) {
  if (err instanceof ToolError && err.message.includes('Invalid cmux relay auth metadata')) {
    // regenerate ~/.cmux/relay/<port>.auth via cmux, or switch to env credentials
  }
  throw err;
}

Prevention

When it happens

Trigger: The .auth file exists but contains missing/empty relay_id or relay_token, a non-hex token (e.g. base64 or raw secret), an odd-length hex token, or wrong JSON field names (not relay_id/relay_token).

Common situations: Hand-edited or truncated .auth file; token pasted in base64 rather than hex; cmux version that wrote a different schema than the client expects; copy-paste dropped characters from the token.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/018a3038663a39ca. Report an issue: GitHub.