{"record":{"id":"b698e0ae1487aab1","repo":"router-for-me/CLIProxyAPI","slug":"missing-access-token-and-refresh-token","errorCode":null,"errorMessage":"missing access_token and refresh_token","messagePattern":"missing access_token and refresh_token","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/fetch_codex_models/main.go","lineNumber":194,"sourceCode":"\t\treturn auth\n\t}\n\treturn nil\n}\n\nfunc ensureAccessToken(ctx context.Context, store *sdkauth.FileTokenStore, auth *coreauth.Auth) (string, bool, error) {\n\taccessToken := metaStringValue(auth.Metadata, \"access_token\")\n\tif accessToken != \"\" {\n\t\tif expiresAt, ok := auth.ExpirationTime(); !ok || time.Now().Add(accessTokenRefreshLeeway).Before(expiresAt) {\n\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","sourceCodeStart":176,"sourceCodeEnd":212,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/cmd/fetch_codex_models/main.go#L176-L212","documentation":"In cmd/fetch_codex_models/main.go the tool resolves an access token from an auth file's metadata. If metadata contains neither a usable `access_token` nor a `refresh_token`, there is no credential to present or refresh, so it fails with `missing access_token and refresh_token`. This always indicates the selected auth file is not a completed Codex OAuth credential (or the keys are named differently).","triggerScenarios":"Running fetch_codex_models with --auth pointing at a JSON file whose metadata lacks both `access_token` and `refresh_token` keys: a hand-written stub file, a partially completed login, an auth file of a different provider type (e.g. Gemini/Qwen), or metadata keys misspelled.","commonSituations":"Reusing an auths/ file from another provider; login flow interrupted before tokens were persisted; manually edited auth JSON that dropped the metadata block; file-level key expected at top level instead of under `metadata`.","solutions":["Re-authenticate Codex via the proxy's OAuth login flow so auths/<file>.json contains a full metadata block with access_token/refresh_token.","Verify the JSON structure: tokens must live under `metadata.access_token` / `metadata.refresh_token`, not at the top level.","Confirm the auth file type is codex (`metadata.type: \"codex\"`) and not another provider's credential.","Point --auth at the correct file in auths/ generated by a successful login."],"exampleFix":"// before: incomplete auth file\n{ \"id\": \"my-auth\", \"type\": \"codex\" }\n\n// after: complete auth file\n{\n  \"id\": \"my-auth\",\n  \"type\": \"codex\",\n  \"metadata\": {\n    \"access_token\": \"...\",\n    \"refresh_token\": \"...\",\n    \"type\": \"codex\"\n  }\n}","handlingStrategy":"validation","validationCode":"// Run before invoking the tool/SDK with an auth file\nfunc authHasCodexTokens(authJSON []byte) bool {\n    meta := gjson.GetBytes(authJSON, \"metadata\")\n    return meta.Get(\"access_token\").String() != \"\" || meta.Get(\"refresh_token\").String() != \"\"\n}","typeGuard":"func isUsableCodexAuth(meta map[string]any) bool {\n    at, _ := meta[\"access_token\"].(string)\n    rt, _ := meta[\"refresh_token\"].(string)\n    return strings.TrimSpace(at) != \"\" || strings.TrimSpace(rt) != \"\"\n}","tryCatchPattern":null,"preventionTips":["Validate the auth file structure (tokens under metadata) before passing it to fetch_codex_models.","Always mint credentials via the proxy's OAuth login flow rather than hand-writing files.","Check metadata.type == \"codex\" to avoid feeding other providers' files to the tool."],"tags":["codex","oauth","credentials","cli"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}