Skip to content

[Bug]: A Muse turn stopped by the subscription quota shows as a provider error, not Limited #18236

Open

Description

@ntindle

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/server

Steps to reproduce

A real run needs a used-up Meta subscription window. To reproduce on demand I put a small proxy between Muse and api.meta.ai (Muse's endpoint_transport setting) that answers POST /v1/responses with HTTP 429 and the body Meta sends for a used-up window:

{"error": {"code": "rate_limit_exceeded", "message": "Subscription quota exhausted. Your usage window resets soon.", "resets_at": 1791730859, "type": "rate_limit_error"}}
  1. Enable the Muse Code provider on a host signed in to a Meta subscription.
  2. Send a Muse thread a message while the quota is used up (or the proxy refuses it).

Expected behavior

The thread is marked Limited, with Resume at reset and Snooze until reset, the way a Codex or Claude turn that hits its limit is. "Auto-resume limited threads" then works for Muse too.

Actual behavior

Muse treats the refusal as a quota stop (error_kind: tier_limit, not retried) and fails the turn with API error 429: Subscription quota exhausted. Your usage window resets soon. (rate_limit_error). T3 shows that as a red "Provider error" and marks the thread Failed, with no reset time and no way to resume at reset. The adapter maps every failed turn to provider_error or transport_error (adapter.ts). Muse also drops the resets_at Meta sends with the refusal.

Impact

Minor bug or occasional failure

Version or commit

main @ ed0f7b9

Environment

Linux (Ubuntu 24.04), web client in Chromium, Node 24.21.0, Muse Code 1.4.4 (1.4.4-R5419.1), muse-spark-1.3-contributor on a Meta subscription

Logs or stack traces

# muse exec --json against the same proxy (Muse 1.4.4), trimmed
task.lifecycle.status  phase=stream_failed  error_kind=tier_limit  http_status=429  "failed meta model stream attempt 1/10"
run.terminal.failed    reason="API error 429: Subscription quota exhausted. Your usage window resets soon. (rate_limit_error)"

Screenshots, recordings, or supporting files

The refused turn and the thread's status on main:

Two red Provider error rows with the raw API error 429 text

The thread marked Failed in the sidebar

Workaround

Wait for the window to reset and send the message again by hand.

Proposed fix

In packages/provider-muse's adapter, when a failed turn's message is Muse's quota refusal (API error 429 with "Subscription quota" or "usage limit"), report it as a usage_limit failure titled "Usage limit reached" instead of provider_error. Its resetAt comes from the newest usage/changed report Muse sent before the refusal: the latest reset among the windows that report showed used up. If no report showed a used-up window, the thread is still Limited, without a reset time. The change includes focused tests for the classification and the reset time, and before/after screenshots on web and mobile.

A working version of this was part of #17151, which was closed for missing screenshots. Once this is triaged I'll open a focused PR for it.

Filed with Claude Opus 5.5 in Claude Code.

Activity

  1. juliusmarminge commented on Oct 11, 2026

    @juliusmarminge
    Member

    Note

    Grok responding on behalf of Julius.

    Bug confirmed on main: Muse's failed-turn path never emits usage_limit. In packages/provider-muse/src/server/adapter.ts, finish() maps every failure to provider_error or transport_error (around the makeProviderFailure call), then turn/completed passes through result.error?.message unchanged. That is why a Meta quota stop (API error 429: Subscription quota exhausted… (rate_limit_error)) shows as a red Provider error and marks the thread Failed.

    Claude (ClaudeAdapterV2), Codex (CodexAdapterV2), and Grok already classify the same kind of stop as usage_limit, which is what drives Limited, Resume at reset, Snooze, and auto-resume. Muse is missing that classification, not a new product surface.

    Related but separate from #18235 (Limits metering — enhancement / Ideas). Closed #17151 covered both; this issue is only the failure class. A focused PR that classifies the quota refusal as usage_limit (and sets resetAt when a prior usage/changed report has it) is welcome — include before/after of the Limited thread state per CONTRIBUTING.md.

  2. added
    bugSomething is broken or behaving incorrectly.
    via-triageFiled through npx t3 triage
    on Oct 11, 2026
  3. added a commit that references this issue on Oct 11, 2026
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

    bugSomething is broken or behaving incorrectly.via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions