router-for-me/CLIProxyAPI · error
failed to save refreshed auth: %w
Error message
failed to save refreshed auth: %w
What it means
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.
Source
Thrown at cmd/fetch_codex_models/main.go:225
auth.Metadata = make(map[string]any)
}
auth.Metadata["id_token"] = tokenData.IDToken
auth.Metadata["access_token"] = tokenData.AccessToken
if tokenData.RefreshToken != "" {
auth.Metadata["refresh_token"] = tokenData.RefreshToken
}
if tokenData.AccountID != "" {
auth.Metadata["account_id"] = tokenData.AccountID
}
if tokenData.Email != "" {
auth.Metadata["email"] = tokenData.Email
}
auth.Metadata["expired"] = tokenData.Expire
auth.Metadata["type"] = "codex"
auth.Metadata["last_refresh"] = time.Now().Format(time.RFC3339)
if _, errSave := store.Save(ctx, auth); errSave != nil {
return "", false, fmt.Errorf("failed to save refreshed auth: %w", errSave)
}
return tokenData.AccessToken, true, nil
}
func fetchModels(ctx context.Context, auth *coreauth.Auth, accessToken, clientVersion string) ([]byte, int, error) {
modelsURL, errURL := codexModelsURL(clientVersion)
if errURL != nil {
return nil, 0, errURL
}
httpReq, errReq := http.NewRequestWithContext(ctx, http.MethodGet, modelsURL, nil)
if errReq != nil {
return nil, 0, errReq
}
httpReq.Close = true
httpReq.Header.Set("Accept", "application/json")
httpReq.Header.Set("Authorization", "Bearer "+accessToken)View on GitHub (pinned to 78f0c4079e)
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.
Example fix
# before: read-only auth dir $ ls -ld auths # dr-x------ root root # after: writable by the runtime user $ chown -R $(id -u):$(id -g) auths && chmod u+w auths
Defensive patterns
Strategy: validation
Validate before calling
// Pre-flight: can we write to the auth store location?
func authStoreWritable(authDir string) bool {
probe := filepath.Join(authDir, ".write-probe")
return os.WriteFile(probe, []byte("x"), 0o600) == nil && os.Remove(probe) == nil
} Type guard
func isAuthSaveFailure(err error) bool {
return err != nil && strings.Contains(err.Error(), "failed to save refreshed auth")
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- failed to create directory: %v
- failed to create token file: %w
- missing access_token and refresh_token
- refresh response did not include access_token
- failed to create directory: %v
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/2a25994477d062e1.
Report an issue: GitHub.