can1357/oh-my-pi · error · ToolError

Missing cmux relay auth metadata for ${endpoint.host}:${endp

Error message

Missing cmux relay auth metadata for ${endpoint.host}:${endpoint.port}; set CMUX_RELAY_ID/CMUX_RELAY_TOKEN or restore ~/.cmux/relay/${endpoint.port}.auth

What it means

When the socket path looks like a TCP relay endpoint (127.0.0.1:<port>), the client needs relay credentials: either CMUX_RELAY_ID/CMUX_RELAY_TOKEN env vars or a JSON file ~/.cmux/relay/<port>.auth. If the env vars are absent/invalid and the auth file cannot be read or parsed as JSON, this ToolError is thrown telling you exactly which source to provide.

Source

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

		const port = Number.parseInt(match[2] ?? "", 10);
		if (!Number.isInteger(port) || port < 1 || port > 65_535) {
			return null;
		}
		return { host: "127.0.0.1", port };
	}

	async #loadRelayCredentials(endpoint: RelayEndpoint): Promise<RelayCredentials> {
		const environmentCredentials = parseRelayCredentials(this.#relayId, this.#relayToken);
		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);

View on GitHub (pinned to 9690622007)

Solutions

  1. Export CMUX_RELAY_ID and CMUX_RELAY_TOKEN (token must be a hex string) before connecting
  2. Restore or regenerate ~/.cmux/relay/<port>.auth containing relay_id and relay_token (match the current relay port)
  3. Verify the relay port in the socket path is the currently running relay; a stale port means the wrong .auth filename

Example fix

// before
new CmuxSocketClient({ socketPath: '127.0.0.1:8931' }) // no creds anywhere
// after
export CMUX_RELAY_ID=relay-abc
export CMUX_RELAY_TOKEN=0f1e2d3c4b5a...
new CmuxSocketClient({ socketPath: '127.0.0.1:8931' })
Defensive patterns

Strategy: validation

Validate before calling

const isHex = (s: unknown): s is string =>
  typeof s === 'string' && s.trim().length > 0 && s.trim().length % 2 === 0 && /^[0-9a-f]+$/i.test(s.trim());
if (!isHex(process.env.CMUX_RELAY_TOKEN) || !process.env.CMUX_RELAY_ID) {
  // check ~/.cmux/relay/<port>.auth exists and is valid JSON before connecting
}

Type guard

function hasRelayCredentials(env: NodeJS.ProcessEnv): boolean {
  return typeof env.CMUX_RELAY_ID === 'string' && env.CMUX_RELAY_ID.length > 0 &&
    typeof env.CMUX_RELAY_TOKEN === 'string' && /^[0-9a-f]+$/i.test(env.CMUX_RELAY_TOKEN.trim()) &&
    env.CMUX_RELAY_TOKEN.trim().length % 2 === 0;
}

Try / catch

try {
  await client.connect();
} catch (err) {
  if (err instanceof ToolError && err.message.startsWith('Missing cmux relay auth metadata')) {
    // load credentials into env from the relay registration output, then retry once
  }
  throw err;
}

Prevention

When it happens

Trigger: Connecting to a `127.0.0.1:<port>` relay endpoint while CMUX_RELAY_ID/CMUX_RELAY_TOKEN are unset or not a valid id+hex-token pair, and ~/.cmux/relay/<port>.auth is missing, unreadable, or not valid JSON.

Common situations: Running the agent outside the cmux environment where the env vars are normally injected; cmux regenerated the relay port so the old .auth filename no longer matches; home directory differs (containers/CI) so the file is absent.

Understand the failure class

Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — 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/364df03230d94fc2. Report an issue: GitHub.