Skip to content

Meta provider sessions fail with client_attestation_denied (403) despite healthy quota picture #818

Closed

Description

@dezren39

Problem

OpenChamber sessions seated on the Meta provider (meta/muse-spark-1.3-contributor) intermittently — then terminally — fail with a provider auth error, even though the Meta quota read reports the pool healthy (Muse Code High Usage plan, 5h 1% used at 2026-10-28 22:32 CDT).

Error (provider.auth, HTTP 403, code client_attestation_denied):

This API key is billed to a Muse Code subscription, and this request does not carry Muse Code's builtin tool declarations. Send it from Muse Code, or use a pay-as-you-go API key for other clients.

Evidence (2026-10-28 ~22:36–22:44 CDT, laptop OpenChamber 2.5.0)

Acceptance

  • Root cause named: which request shape/tool-declaration difference triggers client_attestation_denied for OpenCode's Meta provider calls.
  • Meta-seated OpenChamber sessions complete multi-turn tool-using work again, verified with a scripted multi-turn session, OR the Meta provider configuration is changed so the failing request shape is no longer sent.
  • The failure mode is surfaced somewhere visible (session outcome / quota or provider health) instead of a healthy quota picture masking a dead route.

Acceptance criteria

  • Root cause named: which request shape / tool-declaration difference triggers client_attestation_denied for OpenCode's Meta provider calls.
  • Meta-seated OpenChamber sessions complete multi-turn tool-using work again, verified with a scripted multi-turn session, OR the Meta provider configuration is changed so the failing request shape is no longer sent.
  • The failure mode is surfaced somewhere visible (session outcome / quota or provider health) instead of a healthy quota picture masking a dead route.

Activity

  1. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    priority/highImportant and time-sensitive
    on Oct 29, 2026
  2. developing-today commented on Oct 29, 2026

    @developing-today
  3. added
    effort/mMedium: expected under 1 day of work
    app/corePackage: core (pkgs/ or apps/ in this repo)
    meta/enrichedIntake review done: acceptance criteria, links, and normalized labels added
    on Oct 29, 2026
  4. dezren39 commented on Oct 29, 2026

    @dezren39
    Author

    Intake review

    🤖 Fleet monitor intake enrichment, 2026-10-29. Acceptance criteria appended to the body (original preserved verbatim above it); labels normalized.

  5. dezren39 commented on Oct 29, 2026

    @dezren39
    Author

    Root cause found; route verified healthy; closing.

    What actually happened (from the server's own message store): the client_attestation_denied failures were real but bounded to a ~22-minute window. The store contains exactly 5 denied outcomes, all between 2026-10-29T03:36:41Z and 03:58:06Z (Oct 28, 22:36–22:58 CDT) — the two dispatcher sessions named in this issue plus their retries. In each session the first step completed on meta/muse-spark-1.3-contributor and the next step was denied, which matches a Meta-side attestation enforcement switching on mid-window (a progressive rollout is exactly "intermittent, then terminal"). No client-side change preceded it: provider config, request construction, and credentials are identical to the ones that ran meta sessions successfully earlier the same evening.

    Why it looked down for ~7.5 more hours: after 03:58:06Z the store contains zero denials — and zero completed meta messages until a verification session today at 11:33Z. The fleet never retried inference. The "still down" signal was the quota read (/api/quota/meta → No quota data in response). The meta quota provider reads plan usage from POST https://api.meta.ai/muse-code/key with the Muse CLI's account OAuth token — a different endpoint from inference. That read kept failing (HTTP 200 with no subs_usage and is_subs_active not true) long after inference recovered, and the dispatch gate treats a failed quota read as a closed pool, so the outage became self-sustaining: no sessions seated → inference never re-checked → the failing read stayed the only signal.

    Verification today (2026-10-29 ~11:22–11:40Z), all with the unchanged plan key (sha256 prefix 61a2ae5f; the pay-as-you-go key was never touched):

    • Raw API against https://api.meta.ai/v1: GET /models, chat completions, Responses, and Messages shapes — plain, streaming, with tools, and full two-turn tool round-trips (reasoning + function_call + function_call_output replay) — all HTTP 200.
    • Production path: a real session on the standing OpenCode server (ses_e5e788ff595ffeXDNEy5WvkG2A) seated on meta/muse-spark-1.3-contributor ran a bash tool call and completed with the correct output; outcome succeeded.
    • Quota: /api/quota/meta returns ok: true — 5h window 1% used, weekly 23%, plan "Muse Code High Usage", account admin@drewrypope.com.
    • The Muse CLI login never lapsed: ~/.config/muse/auth.json is untouched since 2026-10-26, its account token (sha256 prefix 5b8afcae) authenticates to the key endpoint (HTTP 200, is_subs_active: true, and the endpoint returns the same minted inference key), and muse exec completes tool-using work. No re-login was needed or performed. Inference requests present the minted key, not the OAuth token, so a CLI re-login would not have changed the denied requests anyway.

    Not determinable from outside: exactly what Meta's gate keyed on inside the window. The error text points at tool declarations, but today the identical declarations pass in every shape, including the full production tool set through the real server. If the window recurs, the evidence to capture is a denied request's full body from within the window.

    Acceptance mapping: (1) root cause named — Meta-side attestation window 03:36:41–03:58:06Z, plus the fleet-side quota-gate masking that extended it; (2) meta-seated sessions complete multi-turn tool-using work again — verified above on the production server; (3) failure-mode surfacing — the inverse masking also happened during the window (quota showed a healthy 1% while inference was being denied). A follow-up is filed in openchamber for the quota-read side: a failed or empty plan-usage read must surface its failure class and age instead of standing in for route state.

    — operator investigation, 2026-10-29

  6. dezren39 commented on Oct 29, 2026

    @dezren39
    Author

    Follow-up for the quota-masking half: developing-today-forks/openchamber#787 — surface the meta quota read's failure class and last-success age so a failed usage read never stands in for route state. Closing this issue as completed on the verification above.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    app/corePackage: core (pkgs/ or apps/ in this repo)effort/mMedium: expected under 1 day of workkind/bugSomething isn't working (prefixed form of the classic bug label)meta/enrichedIntake review done: acceptance criteria, links, and normalized labels addedpriority/highImportant and time-sensitivestatus/needs-triageNot yet triaged; needs a first lookstatus:done

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions