{"record":{"id":"95d7185320858864","repo":"router-for-me/CLIProxyAPI","slug":"refresh-response-did-not-include-access-token","errorCode":null,"errorMessage":"refresh response did not include access_token","messagePattern":"refresh response did not include access_token","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/fetch_codex_models/main.go","lineNumber":203,"sourceCode":"\t\t\treturn accessToken, false, nil\n\t\t}\n\t}\n\n\trefreshToken := metaStringValue(auth.Metadata, \"refresh_token\")\n\tif refreshToken == \"\" {\n\t\tif accessToken != \"\" {\n\t\t\treturn accessToken, false, nil\n\t\t}\n\t\treturn \"\", false, fmt.Errorf(\"missing access_token and refresh_token\")\n\t}\n\n\tsvc := codexauth.NewCodexAuthWithProxyURL(nil, auth.ProxyURL)\n\ttokenData, errRefresh := svc.RefreshTokensWithRetry(ctx, refreshToken, 3)\n\tif errRefresh != nil {\n\t\treturn \"\", false, errRefresh\n\t}\n\tif strings.TrimSpace(tokenData.AccessToken) == \"\" {\n\t\treturn \"\", false, fmt.Errorf(\"refresh response did not include access_token\")\n\t}\n\n\tif auth.Metadata == nil {\n\t\tauth.Metadata = make(map[string]any)\n\t}\n\tauth.Metadata[\"id_token\"] = tokenData.IDToken\n\tauth.Metadata[\"access_token\"] = tokenData.AccessToken\n\tif tokenData.RefreshToken != \"\" {\n\t\tauth.Metadata[\"refresh_token\"] = tokenData.RefreshToken\n\t}\n\tif tokenData.AccountID != \"\" {\n\t\tauth.Metadata[\"account_id\"] = tokenData.AccountID\n\t}\n\tif tokenData.Email != \"\" {\n\t\tauth.Metadata[\"email\"] = tokenData.Email\n\t}\n\tauth.Metadata[\"expired\"] = tokenData.Expire\n\tauth.Metadata[\"type\"] = \"codex\"","sourceCodeStart":185,"sourceCodeEnd":221,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/cmd/fetch_codex_models/main.go#L185-L221","documentation":"After successfully calling RefreshTokensWithRetry in cmd/fetch_codex_models/main.go, the refresh response is inspected for an access token. If `tokenData.AccessToken` is empty/whitespace after trimming, the tool aborts with `refresh response did not include access_token`: the OAuth token endpoint answered 200 but its payload did not contain the expected field, so persisting it would produce an unusable credential.","triggerScenarios":"OpenAI/Codex token endpoint returns a 200 body lacking `access_token` (e.g. only an id_token), the response shape changes after an API update, or a proxy in front mangles the JSON. Retry logic already ran (3 attempts) before this check, so it is not transient throttling.","commonSituations":"Upstream auth API contract change after a Codex client-version bump; an intercepting corporate proxy returning HTML/empty JSON; clock/protocol skew causing the endpoint to return an error body with 200; rare account states where refresh yields no access token.","solutions":["Dump the raw refresh response (temporarily add logging) to see what the endpoint actually returned.","Update the Codex client version string used for the refresh request to match the current Codex CLI.","Remove intercepting proxies or configure proxy settings so the OAuth response is untouched.","Re-run full OAuth login to mint a fresh refresh token, in case the old one triggers a degraded response.","Check CLIProxyAPI issues/releases — an upstream API change likely needs a code fix in the codex auth package."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":"func isMissingAccessTokenError(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"refresh response did not include access_token\")\n}","tryCatchPattern":"token, refreshed, err := ensureToken(ctx, auth)\nif isMissingAccessTokenError(err) {\n    // refresh token likely degraded: fall back to full re-login\n    err = reloginAndReplaceAuthFile(ctx, auth)\n}","preventionTips":["Re-login fully when refresh responses start lacking access_token instead of retrying refresh.","Keep the Codex client version current so the token endpoint contract matches.","Avoid network middleware that rewrites OAuth responses."],"tags":["codex","oauth","refresh-token","upstream-api"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}