{"record":{"id":"9ff83fedbd6e8f47","repo":"coleam00/Archon","slug":"pi-oauth-provider-oauthauth-name-produced-no","errorCode":null,"errorMessage":"Pi OAuth provider '${oauthAuth.name}' produced no apiKey for the stored credential.","messagePattern":"Pi OAuth provider '(.+?)' produced no apiKey for the stored credential\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/providers/src/oauth.ts","lineNumber":190,"sourceCode":"  return {\n    id,\n    usesCallbackServer,\n    async login(callbacks): Promise<OAuthCredential> {\n      const oauthAuth = await loader();\n      return oauthAuth.login(adaptLoginCallbacks(oauthAuth, callbacks));\n    },\n    async refreshToken(credentials, options): Promise<OAuthCredential> {\n      const oauthAuth = await loader();\n      const signal = options?.signal ?? new AbortController().signal;\n      return oauthAuth.refresh(credentials, signal);\n    },\n    async getApiKey(credentials): Promise<{ apiKey: string }> {\n      const oauthAuth = await loader();\n      // toAuth is a side-effect-free derivation ({ apiKey?, headers?, baseUrl? })\n      // from whatever credential it is given — it does NOT check expiry.\n      const auth = await oauthAuth.toAuth(credentials);\n      if (!auth.apiKey) {\n        throw new Error(\n          `Pi OAuth provider '${oauthAuth.name}' produced no apiKey for the stored credential.`\n        );\n      }\n      return { apiKey: auth.apiKey };\n    },\n  };\n}\n\nexport const anthropicOAuthProvider: OAuthProviderInterface = adaptOAuthAuth(\n  'anthropic',\n  () => loadOAuthAuth('anthropic.js', 'anthropicOAuth'),\n  true\n);\nexport const githubCopilotOAuthProvider: OAuthProviderInterface = adaptOAuthAuth(\n  'github-copilot',\n  () => loadOAuthAuth('github-copilot.js', 'githubCopilotOAuth'),\n  false\n);","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/coleam00/Archon/blob/0773b9745896ef0612e709c80845a0f7db315b19/packages/providers/src/oauth.ts#L172-L208","documentation":"getApiKey derives fresh auth state from a stored credential via the provider's oauthAuth.toAuth(). toAuth is a pure derivation and does not check expiry, so an apiKey can legitimately be absent — e.g. the stored credentials are incomplete, expired past refresh, or the provider returned no token. The method throws rather than returning an unusable empty key.","triggerScenarios":"getApiKey(credentials) is invoked with a stored OAuth credential for which toAuth() returns an object with no apiKey (refresh failed to yield a token, credentials shape changed, or provider returned partial auth state).","commonSituations":"Long-lived stored credentials expired beyond refresh window; provider rotated its token response shape after an SDK update; credentials persisted by an older version missing fields the new toAuth expects; corrupted/partial credential row in the store.","solutions":["Delete the stored credential and re-run the provider's login flow to obtain fresh tokens","Inspect the stored credentials for missing/expired fields and refresh them explicitly before calling getApiKey","Verify the installed Pi SDK version matches the adapter (toAuth behavior may have changed)","Check provider-side account status (revoked grants, expired sessions) and re-authorize"],"exampleFix":"// before (stale stored credentials)\nconst { apiKey } = await provider.getApiKey(staleCredentials);\n// after (re-login when derivation yields nothing)\nlet creds = staleCredentials;\nconst auth = await oauthAuth.toAuth(creds);\nif (!auth.apiKey) creds = await login(providerId, callbacks);\nconst { apiKey } = await provider.getApiKey(creds);","handlingStrategy":"try-catch","validationCode":"const auth = await oauthAuth.toAuth(credentials);\nconst needsRelogin = !auth.apiKey;","typeGuard":"function hasApiKey(a: { apiKey?: string }): a is { apiKey: string } {\n  return typeof a.apiKey === 'string' && a.apiKey.length > 0;\n}","tryCatchPattern":"try {\n  return await provider.getApiKey(credentials);\n} catch (err) {\n  if (String(err.message).includes('produced no apiKey')) {\n    const fresh = await runLogin(providerId); // re-authenticate\n    return provider.getApiKey(fresh);\n  }\n  throw err;\n}","preventionTips":["Refresh credentials proactively before expiry instead of relying on toAuth (which does not check expiry)","Store complete credential objects and re-login when their shape/version changes","Monitor for repeated getApiKey failures as a signal credentials are dead"],"tags":["oauth","credentials","token-refresh","providers"],"backgroundTag":"oauth-token-invalid","analyzedSha":"0773b9745896ef0612e709c80845a0f7db315b19","analyzedAt":"2026-09-01T02:28:07.064Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}