Skip to content

bug: OAuth auth + cache_control ephemeral causes HTTP 400 on all Claude models since 2026-03-17 #17910

Closed as not planned

Description

@cyberprophet

Description

All Claude models fail with HTTP 400 when using OAuth authentication (Claude subscription). The error started on 2026-03-17 with no configuration changes. Non-Anthropic models (e.g., GPT-5-nano) work fine.

Root Cause

OpenCode's bundled @ai-sdk/anthropic unconditionally injects cache_control: {"type": "ephemeral"} into system message blocks. This prompt caching metadata appears to no longer be accepted on the OAuth authentication path (Claude subscription). Previously, the Anthropic API silently ignored this field for OAuth requests; as of 2026-03-17, it returns HTTP 400.

Evidence from request body

{
  "model": "claude-sonnet-4-6",
  "max_tokens": 32000,
  "stream": true,
  "system": [
    { "type": "text", "text": "...", "cache_control": { "type": "ephemeral" } },
    { "type": "text", "text": "...", "cache_control": { "type": "ephemeral" } },
    { "type": "text", "text": "..." },
    { "type": "text", "text": "..." }
  ]
}
  • No thinking parameter is present — this is not a thinking/extended-thinking issue.
  • The API response is {"type":"error","error":{"type":"invalid_request_error","message":"Error"}} with status 400.

Confirmed: not a version-specific regression

Tested on both v1.2.27 and v1.2.26 — same error. The cache_control: {"type": "ephemeral"} injection is hardcoded in the bundled @ai-sdk/anthropic (applyCaching()), so downgrading does not help.

Steps to Reproduce

  1. Authenticate via OAuth (opencode providers login anthropic)
  2. Run opencode run "say hello" --model anthropic/claude-sonnet-4-6
  3. → HTTP 400 invalid_request_error

Works fine with API key authentication or non-Anthropic providers.

Expected Fix

When the authentication method is OAuth (Claude subscription), strip cache_control from system blocks before sending to the Anthropic API. Prompt caching is an API-tier feature and should not be applied to OAuth-authenticated requests.

Related

Environment

  • OpenCode: v1.2.26, v1.2.27 (both affected)
  • Auth: OAuth (Claude subscription)
  • OS: Linux (WSL2)

Activity

  1. added
    coreAnything pertaining to core functionality of the application (opencode server stuff)
    on Mar 17, 2026
  2. github-actions commented on Mar 17, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues. Please check:

    • Broken Claude Max #7410: Broken Claude Max — an existing open issue tracking Claude OAuth/subscription failures that may cover the same breakage

    If this is a distinct root cause (specifically the cache_control: ephemeral injection being newly rejected on the OAuth path), it may warrant staying open as a separate, more precise bug report. Please check #7410 to confirm.

  3. cyberprophet commented on Mar 17, 2026

    @cyberprophet
    ContributorAuthor

    Difference from #7410

    #7410 is about Anthropic blocking non-Claude Code clients via system prompt pattern matching (e.g., rejecting requests that contain "opencode" in the system message). The workaround there is injecting "You are Claude Code" into the system prompt.

    This issue is mechanistically different:

    #7410 #17910
    Root cause System prompt content triggers client identity check cache_control: {"type": "ephemeral"} in system blocks triggers invalid_request_error
    Error pattern Credential authorization error ("only for Claude Code") Generic HTTP 400 invalid_request_error with "message": "Error"
    Workaround Inject "You are Claude Code" into system prompt Unknown — cache_control is hardcoded in applyCaching()
    Affected scope OAuth users without opencode-anthropic-auth OAuth users with opencode-anthropic-auth@0.0.13 already installed and working
    Timing Recurring since Jan 2026 Started specifically on 2026-03-17 (worked on 2026-03-16)

    Key evidence

    1. opencode-anthropic-auth is active and has been working — the system prompt already contains "You are Claude Code". This is not a client identity rejection.
    2. The request body shows no thinking parameter — this rules out the thinking/ephemeral conflict described in bug: Claude Sonnet 4.5 with thinking + ephemeral cache returns HTTP 400 #17883.
    3. The only anomaly in the request is cache_control: {"type": "ephemeral"} on system blocks, which is injected by the bundled @ai-sdk/anthropic's applyCaching() and cannot be disabled by plugins.
    4. Same breakage reported independently at [Question]: How does oh-my-opencode map the 'max' variant for native Anthropic provider models like claude-opus-4-6? code-yeongyu/oh-my-openagent#2630 with identical timing (2026-03-16 OK → 2026-03-17 broken, no config change).

    It's possible that Anthropic expanded their OAuth restrictions to reject cache_control (prompt caching is an API-tier feature). But the mechanism and fix path are different from #7410.

  4. added a commit that references this issue on Mar 17, 2026
    2358a0d
  5. cyberprophet commented on Mar 17, 2026

    @cyberprophet
    ContributorAuthor

    Investigation Update: Root cause is not cache_control

    After building from source with a fix that strips cache_control from OAuth requests, the ephemeral metadata was successfully removed from the request body — confirmed via logs. However, the API still returns HTTP 400.

    Direct API testing

    Tested the Anthropic API directly with the stored OAuth access token:

    With Authorization: Bearer header:

    HTTP 401 — {"type":"error","error":{"type":"authentication_error","message":"OAuth authentication is currently not supported."}}
    

    With x-api-key header (how @ai-sdk/anthropic actually sends it):

    HTTP 400 — {"type":"error","error":{"type":"invalid_request_error","message":"Error"}}
    

    Both paths fail even with a minimal request (model + max_tokens + single user message, no cache_control, no thinking, no tools).

    Conclusion

    The root cause is not cache_control: {"type": "ephemeral"}. The Anthropic API appears to have dropped OAuth token support as of 2026-03-17. The vague "message":"Error" response on the x-api-key path is because an OAuth token is not a valid API key.

    This may be an intentional change on Anthropic's side, or a regression in their OAuth infrastructure. Either way, the fix needs to come from the Anthropic API or from how OpenCode's plugin auth layer handles OAuth tokens for the Anthropic provider.

    Environment

    • Tested on: OpenCode built from source (dev branch + cache_control fix)
    • Auth: OAuth (type: "oauth" in auth.json)
    • Token: valid, not expired
  6. HCPTangHY commented on Mar 17, 2026

    @HCPTangHY

    Xerxes-2/clewdr@a4e5df3

    This commit fixed this issue. To put it simply, Anthropic added some new checks for the user-agent and salt values.

  7. R00tedbrain commented on Mar 19, 2026

    @R00tedbrain

    @HCPTangHY how fix now ? my error?

  8. jwcrystal commented on Mar 20, 2026

    @jwcrystal

    Root Cause Update

    Per @cyberprophet's further investigation, the issue is not just about cache_control:

    • Even with cache_control stripped, API still returns HTTP 400
    • Direct API testing with OAuth token fails with minimal requests
    • The x-api-key path returns vague "message": "Error" because OAuth token is not a valid API key

    The Real Fix

    As noted by @HCPTangHY, the actual fix is in clewdr@a4e5df3:

    Anthropic added new validation checks for x-anthropic-billing-header.

    The fix requires:

    1. Generate a billing header with format:

      x-anthropic-billing-header: cc_version=X.X.XX.xxx; cc_entrypoint=cli; cch=00000;
      
    2. The header includes a SHA256 hash based on:

      • SALT + sampled characters from user message + VERSION
    3. Prepend this as a system block to requests

    This essentially mimics Claude Code's billing/authentication flow that Anthropic now requires for OAuth sessions.


    Workaround

    Until OpenCode implements the billing header, use API Key authentication:

    opencode providers login -p anthropic
    # Select "Manually enter API Key"

    Get your API Key from Anthropic Console.


    Note on PR #18311

    PR #18311 addresses the cache_control issue but does not include the x-anthropic-billing-header fix. A more comprehensive fix is needed.

  9. cyberprophet commented on Mar 20, 2026

    @cyberprophet
    ContributorAuthor

    Thanks @jwcrystal for the clean summary.

    To clarify the timeline from my side:

    1. cache_control stripping — I built from source with cache_control removed from OAuth requests. The field was successfully stripped (confirmed via request logging), but the API still returned HTTP 400.
    2. Direct API testing — Minimal curl requests with only an OAuth token and a simple prompt also failed, ruling out any SDK-level issue.
    3. x-api-key path — Using the OAuth token as an API key returns a generic "message": "Error", which is expected since OAuth tokens are not API keys.

    So the root cause is confirmed: Anthropic now requires x-anthropic-billing-header validation for OAuth sessions, as @HCPTangHY pointed out via the clewdr fix.

    Workaround remains API Key authentication for now:

    opencode providers login -p anthropic
    # Select "Manually enter API Key"

    I'll leave it to the maintainers to decide the path forward regarding the billing header requirement.

  10. quarryman commented on Mar 22, 2026

    @quarryman

    Guys, can anyone elaborate? Is it just tecnical limitation easy to overcome by patching headers or there is something legal behind it?

  11. jwcrystal commented on Mar 24, 2026

    @jwcrystal
  12. quarryman commented on Mar 24, 2026

    @quarryman

    @rekram1-node Can you elaborate please?
    I think most are interested to know if there is a plan to have this fixed anytime or the team/owner has any concerns.
    Thanks

  13. r00tedbrain-backup commented on Mar 24, 2026

    @r00tedbrain-backup

    Customer-terms
    Section 2 (prohibiting sharing of credentials) and Section 3.7 (prohibiting automated access of non-API Keys) have covered relevant restrictions

    -.-

  14. rekram1-node commented on Mar 26, 2026

    @rekram1-node
    Contributor

    anthropic has rquested that we do not engage w/ these and that we drop support for oauth entirely. We are required to do so for legal reasons

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

coreAnything pertaining to core functionality of the application (opencode server stuff)

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions