{"record":{"id":"364df03230d94fc2","repo":"can1357/oh-my-pi","slug":"missing-cmux-relay-auth-metadata-for-endpoint-ho","errorCode":null,"errorMessage":"Missing cmux relay auth metadata for ${endpoint.host}:${endpoint.port}; set CMUX_RELAY_ID/CMUX_RELAY_TOKEN or restore ~/.cmux/relay/${endpoint.port}.auth","messagePattern":"Missing cmux relay auth metadata for (.+?):(.+?); set CMUX_RELAY_ID/CMUX_RELAY_TOKEN or restore ~/\\.cmux/relay/(.+?)\\.auth","errorType":"exception","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/browser/cmux/socket-client.ts","lineNumber":203,"sourceCode":"\t\tconst port = Number.parseInt(match[2] ?? \"\", 10);\n\t\tif (!Number.isInteger(port) || port < 1 || port > 65_535) {\n\t\t\treturn null;\n\t\t}\n\t\treturn { host: \"127.0.0.1\", port };\n\t}\n\n\tasync #loadRelayCredentials(endpoint: RelayEndpoint): Promise<RelayCredentials> {\n\t\tconst environmentCredentials = parseRelayCredentials(this.#relayId, this.#relayToken);\n\t\tif (environmentCredentials) {\n\t\t\treturn environmentCredentials;\n\t\t}\n\n\t\tconst authPath = path.join(os.homedir(), \".cmux\", \"relay\", `${endpoint.port}.auth`);\n\t\tlet payload: unknown;\n\t\ttry {\n\t\t\tpayload = await Bun.file(authPath).json();\n\t\t} catch {\n\t\t\tthrow new ToolError(\n\t\t\t\t`Missing cmux relay auth metadata for ${endpoint.host}:${endpoint.port}; set CMUX_RELAY_ID/CMUX_RELAY_TOKEN or restore ~/.cmux/relay/${endpoint.port}.auth`,\n\t\t\t);\n\t\t}\n\t\tconst relayId = payload && typeof payload === \"object\" && \"relay_id\" in payload ? payload.relay_id : undefined;\n\t\tconst relayToken =\n\t\t\tpayload && typeof payload === \"object\" && \"relay_token\" in payload ? payload.relay_token : undefined;\n\t\tconst fileCredentials = parseRelayCredentials(relayId, relayToken);\n\t\tif (!fileCredentials) {\n\t\t\tthrow new ToolError(`Invalid cmux relay auth metadata in ~/.cmux/relay/${endpoint.port}.auth`);\n\t\t}\n\t\treturn fileCredentials;\n\t}\n\n\tasync #authenticateRelay(endpoint: RelayEndpoint, credentials: RelayCredentials): Promise<void> {\n\t\tconst challengeLine = await this.#nextLine(DEFAULT_CONNECT_TIMEOUT_MS);\n\t\tlet challenge: unknown;\n\t\ttry {\n\t\t\tchallenge = JSON.parse(challengeLine);","sourceCodeStart":185,"sourceCodeEnd":221,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/browser/cmux/socket-client.ts#L185-L221","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Export CMUX_RELAY_ID and CMUX_RELAY_TOKEN (token must be a hex string) before connecting","Restore or regenerate ~/.cmux/relay/<port>.auth containing relay_id and relay_token (match the current relay port)","Verify the relay port in the socket path is the currently running relay; a stale port means the wrong .auth filename"],"exampleFix":"// before\nnew CmuxSocketClient({ socketPath: '127.0.0.1:8931' }) // no creds anywhere\n// after\nexport CMUX_RELAY_ID=relay-abc\nexport CMUX_RELAY_TOKEN=0f1e2d3c4b5a...\nnew CmuxSocketClient({ socketPath: '127.0.0.1:8931' })","handlingStrategy":"validation","validationCode":"const isHex = (s: unknown): s is string =>\n  typeof s === 'string' && s.trim().length > 0 && s.trim().length % 2 === 0 && /^[0-9a-f]+$/i.test(s.trim());\nif (!isHex(process.env.CMUX_RELAY_TOKEN) || !process.env.CMUX_RELAY_ID) {\n  // check ~/.cmux/relay/<port>.auth exists and is valid JSON before connecting\n}","typeGuard":"function hasRelayCredentials(env: NodeJS.ProcessEnv): boolean {\n  return typeof env.CMUX_RELAY_ID === 'string' && env.CMUX_RELAY_ID.length > 0 &&\n    typeof env.CMUX_RELAY_TOKEN === 'string' && /^[0-9a-f]+$/i.test(env.CMUX_RELAY_TOKEN.trim()) &&\n    env.CMUX_RELAY_TOKEN.trim().length % 2 === 0;\n}","tryCatchPattern":"try {\n  await client.connect();\n} catch (err) {\n  if (err instanceof ToolError && err.message.startsWith('Missing cmux relay auth metadata')) {\n    // load credentials into env from the relay registration output, then retry once\n  }\n  throw err;\n}","preventionTips":["Set CMUX_RELAY_ID/CMUX_RELAY_TOKEN in the environment the agent runs in (cmux injects them natively)","Keep ~/.cmux/relay/<port>.auth intact — do not clean it with home-dir sweeps","Re-derive the auth filename after relay port changes","Validate the token is hex before storing it"],"tags":["auth","config","relay","missing-file"],"backgroundTag":"missing-env-var","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}