Skip to content

fix(auth): classify OAuth token errors as connection/login, not internal - #2788

Open
dhnihaoya wants to merge 2 commits into
MoonshotAI:mainfrom
dhnihaoya:fix/oauth-connection-error-classification
Open

fix(auth): classify OAuth token errors as connection/login, not internal#2788
dhnihaoya wants to merge 2 commits into
MoonshotAI:mainfrom
dhnihaoya:fix/oauth-connection-error-classification

Conversation

@dhnihaoya

Copy link
Copy Markdown

Related Issue

Resolve #2786

Problem

See linked issue (#2786). In short: on the default v2 engine (and the v1 daemon / legacy path), an OAuth token-fetch failure during a running task — e.g. a transient auth-host connect timeout — surfaced to the user as [internal] instead of a retryable provider.connection_error. That lost the retryable flag and routed the goal to the generic runtime pause reason instead of the dedicated connection pause, so a brief network blip broke long-running tasks.

Root cause: the OAuth-error → public-error-code classification (mapOAuthTokenError) existed only in @moonshot-ai/kimi-code-sdk's AuthFacade. The token providers handed out by agent-core's ManagedAuthFacade.resolveOAuthTokenProvider and agent-core-v2's OAuthService.resolveTokenProvider propagated raw OAuthConnectionErrors, which serialize as internal.

What changed

Wrap the two unwrapped token-provider factories so getAccessToken classifies OAuth failures into the public coded errors at the auth-domain boundary (v2 _base/errors forbids importing business domains, so the translation belongs at the boundary, not in the central serializer):

  • packages/agent-core/src/services/auth/managedAuth.tsresolveOAuthTokenProvider now wraps the provider; added mapOAuthTokenError (mirrors the SDK helper; kept local because agent-core cannot import the SDK).
  • packages/agent-core-v2/src/app/auth/authService.tsresolveTokenProvider now wraps the provider; added classifyOAuthTokenError.

Mapping (matches the existing SDK behavior):

  • OAuthConnectionError / RetryableRefreshErrorprovider.connection_error (retryable)
  • OAuthUnauthorizedErrorauth.login_required
  • anything else → rethrown raw (no false classification)

getCachedAccessToken is intentionally left unwrapped: it only reads local token storage (no HTTP / refresh), so it cannot produce these OAuth errors — wrapping it would be a no-op.

node-sdk is untouched (its facade already classifies). The now-triplicated classification logic is tracked for consolidation in #2787.

Tests added to the existing test files (v1 oauth-service.test.ts, v2 auth.test.ts): each path covers the connection mapping, the unauthorized mapping, and the "rethrow unrecognized raw" case. 81 relevant tests pass; both packages tsc --noEmit clean.

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked a related issue, or explained the problem above.
  • I have added tests that prove my feature works.
  • Ran gen-changesets skill, or this PR needs no changeset.
  • Ran gen-docs skill, or this PR needs no doc update.

OAuth token-fetch failures (transport timeout, unauthorized refresh) reached
the UI as `[internal]` on the default v2 engine and the v1 daemon path,
because the token providers handed out by `AuthService.resolveTokenProvider`
(agent-core-v2) and `ManagedAuthFacade.resolveOAuthTokenProvider` (agent-core)
propagated raw `OAuthConnectionError`s. The classification only existed in
node-sdk's facade.

Wrap both facades so `getAccessToken` maps the oauth error classes to the
public coded errors at the auth-domain boundary (v2 `_base/errors` forbids
importing business domains, so the translation belongs here):
  - OAuthConnectionError / RetryableRefreshError -> provider.connection_error (retryable)
  - OAuthUnauthorizedError -> auth.login_required

This restores the retryable flag and the dedicated pause reason, so a
transient auth-host outage during a long task surfaces correctly instead of
breaking the session.

Refs: MoonshotAI#2786
@changeset-bot

changeset-bot Bot commented Aug 10, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 87e2efb

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@moonshot-ai/kimi-code Patch
@moonshot-ai/agent-core Patch
@moonshot-ai/agent-core-v2 Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a020fc4bec

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +273 to +275
// Classify OAuth token failures into coded `Error2`s at the auth-domain
// boundary (`_base/errors` deliberately never imports a business domain, so
// the translation must happen here — see `_base/errors/serialize.ts`).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Remove the body comment from the v2 auth path

This new explanatory comment sits inside the implementation body, but the v2 package convention keeps comments solely in the top-of-file header and never beside methods/statements. The rationale here belongs in the commit/tests or, if it changes the module's external role, in the file header; leaving it inline makes the file violate the scoped comment rule.

AGENTS.md reference: packages/agent-core-v2/AGENTS.md:L36-L38

Useful? React with 👍 / 👎.

Comment on lines +199 to +203
/**
* Classify an OAuth token-fetch failure into the public {@link KimiError}
* protocol so callers (turn serialization, SDK clients) can react on `code`
* rather than on class identity.
*

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Drop the helper docstring in services code

This added block comment documents an internal helper in packages/agent-core/src/services, where the scoped guide explicitly forbids block/paragraph docstrings on internal helpers. Please remove it or reduce it to a single non-obvious invariant if one is truly needed, so the source does not accumulate rationale that belongs in the change history.

AGENTS.md reference: packages/agent-core/src/services/AGENTS.md:L170-L173

Useful? React with 👍 / 👎.

agent-core-v2 keeps comments in the top-of-file header only (never beside
functions/statements), and agent-core/services forbids block docstrings on
internal helpers and diff-narrating comments. Remove the inline rationale
added with the OAuth error classification so the new code matches each
package's convention.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OAuth 连接错误显示成 [internal] 而非 provider.connection_error,丢失 retryable 标志和专属暂停原因

1 participant