{"record":{"id":"8eaba03cf152a14a","repo":"musistudio/claude-code-router","slug":"grok-cli-oidc-discovery-did-not-return-a-token-end","errorCode":null,"errorMessage":"Grok CLI OIDC discovery did not return a token endpoint.","messagePattern":"Grok CLI OIDC discovery did not return a token endpoint\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/agents/local-providers/grok.ts","lineNumber":753,"sourceCode":"  }\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 {\n    const response = await fetchWithSystemProxy(metadataUrl, {\n      headers: { accept: \"application/json\" },\n      signal: controller.signal\n    });\n    const text = await response.text();\n    const payload = parseJsonRecord(text);\n    if (!response.ok) {\n      throw new Error(`Grok CLI OIDC discovery returned HTTP ${response.status}${tokenRefreshErrorMessage(payload, text)}`);\n    }\n    const tokenEndpoint = readString(payload?.token_endpoint) || readString(payload?.tokenEndpoint);\n    if (!tokenEndpoint) {\n      throw new Error(\"Grok CLI OIDC discovery did not return a token endpoint.\");\n    }\n    return tokenEndpoint;\n  } catch (error) {\n    if (error instanceof Error && error.name === \"AbortError\") {\n      throw new Error(`Grok CLI OIDC discovery timed out after ${timeoutMs}ms.`);\n    }\n    throw error;\n  } finally {\n    clearTimeout(timer);\n  }\n}\n\nfunction grokCredentialFiles(): string[] {\n  const explicitFile = process.env.GROK_AUTH_FILE?.trim();\n  return uniqueStrings([\n    explicitFile,\n    path.join(grokStorageRoot(), \"auth.json\"),\n    path.join(grokStorageRoot(), \"credentials.json\")","sourceCodeStart":735,"sourceCodeEnd":771,"githubUrl":"https://github.com/musistudio/claude-code-router/blob/99f24806c6a2c660b16e53e95211c517448a6c90/packages/core/src/agents/local-providers/grok.ts#L735-L771","documentation":"OIDC discovery for Grok succeeded at the HTTP level but the returned JSON lacked a token_endpoint (or tokenEndpoint) string, so no OAuth token URL could be derived. The library throws instead of guessing an endpoint.","triggerScenarios":"The discovery document JSON parses but has no token_endpoint/tokenEndpoint field — a truncated body, a non-standard discovery document, or the URL pointing at a JSON resource that is not an OIDC configuration.","commonSituations":"Discovery URL points at the wrong well-known path; provider ships a partial/preview document; a proxy rewrites the response body.","solutions":["Fetch the discovery URL manually and inspect the JSON for token_endpoint","Re-run login to regenerate the cached discovery URL","Verify the issuer matches the actual OIDC provider host","Report if the provider changed the discovery schema"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const doc = await fetch(discoveryUrl).then(r => r.json());\nif (typeof doc.token_endpoint !== 'string' || !doc.token_endpoint) {\n  throw new Error('discovery document lacks token_endpoint — refresh login config');\n}","typeGuard":null,"tryCatchPattern":"catch (e) {\n  if (e instanceof Error && e.message.includes('did not return a token endpoint')) {\n    await relogin(); // cached discovery URL is wrong\n  }\n}","preventionTips":["Validate discovery documents once and cache the validated token endpoint","Fail fast on schema drift instead of falling back to guessed endpoints"],"tags":["oidc","discovery","grok","malformed-response"],"backgroundTag":"oidc-discovery-failed","analyzedSha":"99f24806c6a2c660b16e53e95211c517448a6c90","analyzedAt":"2026-08-27T04:11:01.184Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}