{"record":{"id":"621dd4d8332f763c","repo":"musistudio/claude-code-router","slug":"grok-cli-oauth-token-refresh-timed-out-after-tim","errorCode":null,"errorMessage":"Grok CLI OAuth token refresh timed out after ${timeoutMs}ms.","messagePattern":"Grok CLI OAuth token refresh timed out after (.+?)ms\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/agents/local-providers/grok.ts","lineNumber":723,"sourceCode":"        throw new GrokRefreshAuthError(response.status, message);\n      }\n      throw new Error(message);\n    }\n    const accessToken = readString(payload?.access_token) || readString(payload?.accessToken);\n    if (!accessToken) {\n      throw new Error(\"Grok CLI OAuth token refresh did not return an access token.\");\n    }\n    const refreshed: GrokTokenSet = {\n      ...auth,\n      accessToken,\n      expiresAt: refreshedGrokExpiresAt(accessToken, payload),\n      refreshToken: readString(payload?.refresh_token) || readString(payload?.refreshToken) || refreshToken\n    };\n    persistRefreshedGrokAuth(refreshed);\n    return refreshed;\n  } catch (error) {\n    if (error instanceof Error && error.name === \"AbortError\") {\n      throw new Error(`Grok CLI OAuth token refresh timed out after ${timeoutMs}ms.`);\n    }\n    throw error;\n  } finally {\n    clearTimeout(timer);\n  }\n}\n\nasync function grokTokenEndpoint(auth: GrokTokenSet): Promise<string> {\n  const configured = readString(process.env.GROK_OIDC_TOKEN_ENDPOINT);\n  if (configured) {\n    return configured;\n  }\n  const issuer = (auth.oidcIssuer || readString(process.env.GROK_OIDC_ISSUER) || grokDefaultOidcIssuer).replace(/\\/+$/, \"\");\n  const metadataUrl = `${issuer}/.well-known/openid-configuration`;\n  const timeoutMs = normalizeGrokOauthTimeout(process.env.GROK_OIDC_REFRESH_TIMEOUT_MS);\n  const controller = new AbortController();\n  const timer = setTimeout(() => controller.abort(), timeoutMs);\n  try {","sourceCodeStart":705,"sourceCodeEnd":741,"githubUrl":"https://github.com/musistudio/claude-code-router/blob/99f24806c6a2c660b16e53e95211c517448a6c90/packages/core/src/agents/local-providers/grok.ts#L705-L741","documentation":"The fetch to the Grok OAuth token endpoint was aborted by an AbortController timer before completing, and the resulting AbortError is rethrown as a descriptive timeout. It indicates the refresh HTTP request exceeded kimiOauth/grokOauth refresh timeoutMs.","triggerScenarios":"refreshGrokAuth's fetch (or response.text()) takes longer than the configured timeoutMs, controller.abort() fires, and the catch converts the AbortError into this message.","commonSituations":"Slow or blocked network egress, DNS black-holing, an intercepting proxy that hangs on POST bodies, or the token endpoint being temporarily unreachable during provider incidents.","solutions":["Retry the operation — transient network slowness is the most common cause","Check connectivity/curl the token endpoint directly to measure latency","Route around VPN/proxies that stall the request","If it consistently times out, check for firewall rules blocking the OAuth host"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"const start = Date.now();\nconst reachable = await pingEndpoint(tokenEndpoint, 2000);\nif (!reachable) skipRefreshForNow();","typeGuard":null,"tryCatchPattern":"catch (e) {\n  if (e instanceof Error && e.message.includes('timed out')) {\n    await sleep(backoffMs(attempt++)); // retryable\n  }\n}","preventionTips":["Wrap refresh in a retry loop with exponential backoff for timeout-class errors","Pre-check network connectivity before launching OAuth flows","Cap total retries to avoid hanging the agent startup"],"tags":["timeout","oauth","grok","network","abort"],"backgroundTag":"http-request-timeout","analyzedSha":"99f24806c6a2c660b16e53e95211c517448a6c90","analyzedAt":"2026-08-27T04:11:01.184Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}