fix(auth-profiles): make post-success bookkeeping saves non-fatal#67064
fix(auth-profiles): make post-success bookkeeping saves non-fatal#67064ademczuk wants to merge 1 commit into
Conversation
Greptile SummaryWraps the bodies of Confidence Score: 5/5Safe to merge — targeted error-path change with zero impact on the happy path and full regression test coverage. All three modified functions are post-completion bookkeeping with no caller-visible contract on the error path. The try/catch scope is tight, in-memory state degradation on EPERM is intentional and documented, and the test file directly exercises the exact failure mode from the issue. No P0 or P1 findings. No files require special attention. Reviews (1): Last reviewed commit: "fix(auth-profiles): make post-success bo..." | Re-trigger Greptile |
|
Closing to recreate from a clean base. The branch was cut from a stale fork main and went DIRTY on submission. Will resubmit from upstream HEAD with the same fix. |
Summary
Fixes #62099. On Windows, concurrent config hot-reload can leave
auth-profiles.jsonwith a ReadOnly attribute. The atomic write insaveAuthProfileStorethen throwsEPERM, and becausemarkAuthProfileGood/markAuthProfileUsed/markAuthProfileFailurerun as post-completion bookkeeping, that throw used to cascade into the LLM request that had already succeeded. Fallback triggers, hits the same read-only file, fails the same way. The gateway becomes unresponsive; restarts don't help because the file attribute persists.The fix wraps the body of each
mark*function in try/catch, logging the persistence failure and continuing. Caller-visible behavior is unchanged on the happy path.What this does NOT change
saveAuthProfileStoreitself still throws on failure. OAuth token refresh (inoauth.ts) depends on that behavior, since a silent token-save failure would be a security concern. Only the threemark*functions that run after a successful provider call now tolerate save errors.Scope
src/agents/auth-profiles/profiles.ts- wrapmarkAuthProfileGoodbody in try/catch, log warnsrc/agents/auth-profiles/usage.ts- wrapmarkAuthProfileUsedandmarkAuthProfileFailurebodies in try/catch, log warnsrc/agents/auth-profiles/usage.persist-nonfatal.test.ts- new regression tests, one per mark function, simulating EPERM from both the lock-guarded and direct save pathsmarkAuthProfileCooldowndelegates tomarkAuthProfileFailureso it's covered transitively.Before
The LLM response arrived, then the save threw, then every fallback hit the same file, then the gateway ran out of models. User hits
attrib -Ron the file and restarts to recover.After
The save throws, the catch runs, the warning lands in the subsystem log, the mark function returns void, the LLM request completes normally.
lastGood/ usage stats stay slightly stale until the next successful save, which is the right tradeoff for a bookkeeping write.Testing
usage.persist-nonfatal.test.tspass (3/3). Mocks bothupdateAuthProfileStoreWithLockandsaveAuthProfileStoreto throw EPERM, asserts themark*functions resolve without throwing.usage.test.ts(39 tests) andauth-profiles.markauthprofilefailure.test.ts(9 tests) still pass. Also verifiedauth-profiles.runtime-snapshot-save.test.ts(1 test).state-observation.test.tsandoauth.fallback-to-main-agent.test.tsalready fail on main, unrelated to this change.oxlint --type-awareclean on modified files.tsgo --noEmitclean (exit 0).oxfmt --checkclean.Risk
Low. Behavioral change is scoped to the error path of a bookkeeping function. Callers that previously got an unhandled rejection on EPERM now get a resolved promise, which is the intended outcome. Profile state in memory stays authoritative; disk just gets slightly stale until the next successful write.
AI disclosure
This change was drafted with Claude Code acting as coding assistant. The issue was picked from the triaged backlog, the root-cause analysis and implementation plan were produced interactively, and tests were written against the exact stack trace in the issue report. Human review of the patch and regression tests before submission.
Understanding confirmation
Yes, I've read CONTRIBUTING.md and VISION.md. This is a single-concern bug fix with no dependency updates, no schema changes, and no new public APIs. The affected module is
src/agents/auth-profiles/. No Carbon changes, no@ts-nocheck, no lint suppression.