{"record":{"id":"2a25994477d062e1","repo":"router-for-me/CLIProxyAPI","slug":"failed-to-save-refreshed-auth-w","errorCode":null,"errorMessage":"failed to save refreshed auth: %w","messagePattern":"failed to save refreshed auth: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/fetch_codex_models/main.go","lineNumber":225,"sourceCode":"\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\"\n\tauth.Metadata[\"last_refresh\"] = time.Now().Format(time.RFC3339)\n\n\tif _, errSave := store.Save(ctx, auth); errSave != nil {\n\t\treturn \"\", false, fmt.Errorf(\"failed to save refreshed auth: %w\", errSave)\n\t}\n\n\treturn tokenData.AccessToken, true, nil\n}\n\nfunc fetchModels(ctx context.Context, auth *coreauth.Auth, accessToken, clientVersion string) ([]byte, int, error) {\n\tmodelsURL, errURL := codexModelsURL(clientVersion)\n\tif errURL != nil {\n\t\treturn nil, 0, errURL\n\t}\n\n\thttpReq, errReq := http.NewRequestWithContext(ctx, http.MethodGet, modelsURL, nil)\n\tif errReq != nil {\n\t\treturn nil, 0, errReq\n\t}\n\thttpReq.Close = true\n\thttpReq.Header.Set(\"Accept\", \"application/json\")\n\thttpReq.Header.Set(\"Authorization\", \"Bearer \"+accessToken)","sourceCodeStart":207,"sourceCodeEnd":243,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/cmd/fetch_codex_models/main.go#L207-L243","documentation":"fetch_codex_models refreshes tokens successfully, mutates auth.Metadata in memory, then persists via store.Save. If Save fails, the error wraps as `failed to save refreshed auth: %w` — the refresh worked (and the rotated refresh token may now be consumed upstream) but the new credential never reached disk/store, so the stale file remains.","triggerScenarios":"auths/ directory or auth file is read-only or owned by another user; disk full; Postgres/git/object-store backend (PGSTORE_*/GITSTORE_*/OBJECTSTORE_* env) unreachable or schema-locked; file locked by a concurrent process; container with a read-only volume mount.","commonSituations":"Running the tool in Docker without write permission on the mounted auths volume; SELinux/AppArmor denying writes; running as a different user than the one that created auths/; storage backend env vars set but backend down.","solutions":["Check the wrapped error's cause: permission denied -> fix ownership/permissions of auths/ (chown/chmod); IO error -> check disk space.","Verify the store backend: if PGSTORE_*/GITSTORE_*/OBJECTSTORE_* is configured, ensure the backend is reachable and credentials valid.","Re-run the tool after fixing write access — and re-login if the old refresh token was already rotated and lost.","In containers, mount auths/ as a writable volume owned by the process user."],"exampleFix":"# before: read-only auth dir\n$ ls -ld auths  # dr-x------ root root\n\n# after: writable by the runtime user\n$ chown -R $(id -u):$(id -g) auths && chmod u+w auths","handlingStrategy":"validation","validationCode":"// Pre-flight: can we write to the auth store location?\nfunc authStoreWritable(authDir string) bool {\n    probe := filepath.Join(authDir, \".write-probe\")\n    return os.WriteFile(probe, []byte(\"x\"), 0o600) == nil && os.Remove(probe) == nil\n}","typeGuard":"func isAuthSaveFailure(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"failed to save refreshed auth\")\n}","tryCatchPattern":null,"preventionTips":["Verify write permission on auths/ (and reachability of PG/git/object store backends) before running the tool.","Run the process as the user that owns the auth directory.","Back up auth files before scripted runs: a consumed-but-unsaved refresh token forces re-login."],"tags":["codex","storage","permissions","oauth"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}