#3273·Archon

bug(providers): one unrefreshable Pi credential fails sessions and catalog refreshes for every other provider

Author: WirasmCreated Sep 10, 2026Updated Sep 14, 2026
Labelsbugarea: clientsP2effort/mediumresearch

Problem

An expired Anthropic OAuth credential in Pi's auth storage stops Pi work that has nothing to do with Anthropic. Observed twice on this install, 9 Sep 2026, with Pi 0.84.4:

1. A Pi session on a different provider fails. archon workflow run e2e-pi-smoke --config .archon/config.gemini.yaml. The session started on OpenAI Codex — pi.session_started logged piProvider: "openai-codex", modelId: "gpt-5.6-sol" — and then failed:

ModelsError: OAuth refresh failed for anthropic: Anthropic token refresh request failed.
url=https://platform.claude.com/v1/oauth/token; status=400;
body={"error": "invalid_grant", "error_description": "Refresh token expired"}
  at resolveStoredOAuth (pi-ai/dist/auth/resolve.js:77)
  at resolveStoredOAuth (pi-coding-agent/dist/core/auth-storage.js:383)
  at ModelsImpl.resolveRefreshCredential

The node failed, its downstream node was skipped, and the run failed. No Anthropic model was configured anywhere in that run.

2. Catalog refresh aborts entirely. pi update --models fails with the same Anthropic error and refreshes nothing, for any provider.

The practical effect is that every Pi-provider config on the install is dead at once — gemini, gemini-glm, minimax, glm-flash — from one unrelated expired credential, and the only recovery is an interactive Anthropic re-login.

Why this is wrong, not just inconvenient

pi-ai's resolver is per-provider by construction. resolveProviderAuth(provider, credentials, authContext, overrides) takes one provider and resolves only that one, and the file's own doc comment states the intent:

Auth resolution shared by the Models and ImagesModels collections. A stored credential owns the provider: ambient/env is consulted only when nothing is stored. No silent env fallback after a failed refresh.

So the design already says an expired Anthropic token should make Anthropic unavailable and nothing else. Something upstream of that function is resolving credentials for providers the run does not use, and one hard failure aborts the batch rather than marking that provider unavailable.

This also breaks the failure-isolation expectation an operator holds. Losing a provider you are not using should not cost you the providers you are.

Why now

It is currently blocking maintainer dogfooding: no Pi workflow can run on this install regardless of config, which is how it was found. It will recur for any user whose Anthropic OAuth grant expires while they are working on another provider, and OAuth grants expire on their own schedule with no warning.

What is not yet established

This is written as an investigation, not a fix, because the owner is genuinely undetermined. Two candidates, neither ruled out:

  • Pi. Something in ModelRuntime.create() or the models collection enumerates stored credentials and resolves each, so an unrelated provider's refresh failure propagates. If so, the fix is upstream and Archon's job is to report it and decide whether to tolerate it.
  • Archon. packages/core/src/credentials/delivery.ts:158 injects ANTHROPIC_OAUTH_TOKEN into Pi sessions, and packages/providers/src/community/pi/provider.ts:217 maps anthropic to that variable. If delivery puts an Anthropic credential in play for every Pi session regardless of the configured provider, the coupling is ours.

Reproduction needs an expired — not merely absent — Anthropic OAuth credential in Pi's auth storage, which is why this was not caught earlier and why the investigation should construct that state deliberately rather than wait for it.

Desired outcome

A provider whose stored credential cannot be refreshed becomes unavailable on its own. Sessions and catalog refreshes for other providers continue, and the operator is told which provider is unusable and why.

Invariants

  • No silent fallback. A provider that cannot authenticate must not quietly resolve to ambient env or to a different provider. pi-ai's comment already forbids this and the fix must not weaken it.
  • The run that actually needs the broken provider still fails, loudly, naming the provider and the reason.
  • No credential values in logs or errors. The existing error text carries the endpoint and the invalid_grant code, not the token; keep it that way.
  • Do not broaden delivery to compensate. If the cause turns out to be Archon injecting credentials for providers a run does not use, the fix is to stop doing that, not to add a repair path.

Acceptance

  • The causal chain is proven with a deliberate reproduction, and the owning layer — Pi or Archon — is named with evidence.
  • With an expired Anthropic OAuth credential present, a Pi node configured for a non-Anthropic provider runs to completion.
  • With the same state, a run configured for Anthropic fails with a message naming Anthropic and the refresh failure.
  • If the owner is Archon, a regression test covers a Pi session for provider X not resolving credentials for provider Y.
  • If the owner is Pi, the finding is reported upstream and the issue records whether Archon tolerates, works around, or waits.

Evidence

  • Failed smoke run: e2e-pi-smoke, 9 Sep 2026, .archon/config.gemini.yaml, node simple failed, node assert skipped.
  • pi-coding-agent / pi-ai 0.84.4, from node_modules, not the global 0.84.4 CLI (see #3272 for why those differ).
  • pi update --models on the global install fails identically, so the behaviour is not specific to Archon's embedding.