{"record":{"id":"5989a4ad7069c17d","repo":"stablyai/orca","slug":"relay-director-resolve-failed-response-status","errorCode":null,"errorMessage":"relay director resolve failed (${response.status})","messagePattern":"relay director resolve failed \\((.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mobile/src/transport/mobile-relay-resume-director.ts","lineNumber":35,"sourceCode":"  fetchImpl?: typeof fetch\n  timeoutMs?: number\n}): Promise<MobileRelayEndpoint> {\n  const controller = new AbortController()\n  const timer = setTimeout(() => controller.abort(), args.timeoutMs ?? 5000)\n  try {\n    const url = new URL('/v1/resolve', args.relay.directorUrl)\n    const response = await (args.fetchImpl ?? fetch)(url.toString(), {\n      method: 'POST',\n      headers: { 'content-type': 'application/json' },\n      body: JSON.stringify({\n        v: 1,\n        relayHostId: args.relay.relayHostId,\n        resumeToken: args.resumeToken\n      }),\n      signal: controller.signal\n    })\n    if (!response.ok) {\n      throw new Error(`relay director resolve failed (${response.status})`)\n    }\n    const declaredLength = Number(response.headers.get('content-length') ?? 0)\n    if (declaredLength > MAX_RESPONSE_BYTES) {\n      throw new Error('relay director resolve response too large')\n    }\n    const raw = await response.text()\n    if (new TextEncoder().encode(raw).byteLength > MAX_RESPONSE_BYTES) {\n      throw new Error('relay director resolve response too large')\n    }\n    const resolved = ResolveResponseSchema.parse(JSON.parse(raw) as unknown)\n    return {\n      ...args.relay,\n      cellUrl: resolved.cellUrl,\n      assignmentEpoch: resolved.assignmentEpoch\n    }\n  } finally {\n    clearTimeout(timer)\n  }","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/mobile/src/transport/mobile-relay-resume-director.ts#L17-L53","documentation":"Thrown in resolveMobileRelayEndpoint when the POST to /v1/resolve returned a non-2xx status. The resume director rejected the resolution: bad/unknown resume token, unknown relayHostId, auth failure, or a server-side error.","triggerScenarios":"Resume token invalid or expired; relayHostId unknown to the director; director returned 401/403 (auth), 404 (unknown host), or 5xx (server fault); wrong directorUrl configured.","commonSituations":"Resume token from an old assignment epoch; director redeployed and lost state; a stale/incorrect directorUrl in MobileRelayEndpoint; transient director outage.","solutions":["Branch on response.status: 401/403 -> token/auth issue, 404 -> unknown host, 5xx -> retry with backoff.","For permanent rejections (4xx), fall back to a fresh pair instead of retrying the same token.","Verify relay.directorUrl and relay.relayHostId match the assigned relay.","Retry with exponential backoff for 5xx/transient failures, respecting timeoutMs."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"async function resolveWithFallback(args: Parameters<typeof resolveMobileRelayEndpoint>[0]) {\n  try {\n    return await resolveMobileRelayEndpoint(args)\n  } catch (error) {\n    const msg = error instanceof Error ? error.message : ''\n    const m = msg.match(/relay director resolve failed \\((\\d+)\\)/)\n    const status = m ? Number(m[1]) : 0\n    if (status >= 500) {\n      // transient: retry with backoff\n      return await resolveMobileRelayEndpoint(args)\n    }\n    if (status >= 400) {\n      // permanent: fall back to a fresh pair\n      throw error\n    }\n    throw error\n  }\n}","preventionTips":["Verify relay.directorUrl and relay.relayHostId are current before resolving.","Retry only 5xx/transient statuses with exponential backoff; treat 4xx as permanent.","Fall back to a fresh pair when the resume token is permanently rejected."],"tags":["relay","network","http","resume","director"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}