Skip to content

[Bug]: Mobile "Resume queue" silently does nothing on a usage-limited thread #27187

Open

Description

@AbdelrahmanTamer21

Before submitting

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

Area

Mobile app (with server orchestration v2)

Steps to reproduce

  1. Start a Claude thread and send a message while it is running, so the message is queued.
  2. Let the running turn fail with a usage limit (a 429 / usage_limit failure).
  3. Once capacity is back (limit reset, or another account added), open the thread in the iOS app.
  4. Tap the composer's Resume queue (play) button.

Expected behavior

The stopped run continues ("Continue where you left off."), then the queued message runs. This is what the web app does.

Actual behavior

Nothing happens on the phone. No error is shown. The server rejects every tap:

OrchestrationV2DispatchCommandError: Continue the limited thread before resuming its queue.
  command: queue.resume

Root cause

  • The mobile app only sends queue.resume. handleResumeQueue in apps/mobile/src/features/threads/ThreadRouteScreen.tsx:690 calls resumeThreadQueue and nothing else. The button only appears when composer.queueHeld is true (line 1080). Mobile never sends a manual continuation: manualContinuationOfRunId doesn't appear anywhere under apps/mobile.
  • The server refuses queue.resume while a usage limit is holding the queue. See apps/server/src/orchestration-v2/Orchestrator.ts:12715-12727 (usageLimitHoldsQueue). It wants the failed run continued first.
  • The web app already handles this correctly. ChatView.tsx:817 computes resumableRunId from the latest run: either it was interrupted, or it failed and latestRootProviderFailure(...) reports class === "usage_limit". Then useComposerResume.ts:105-141 sends startTurn with manualContinuationOfRunId first, and only then resumeThreadQueue.
  • The failure is silent. runAtomCommand reports to console by default (packages/client-runtime/src/state/runtime.ts:340), and the mobile handleResumeQueue ignores the result, so the user gets no feedback.

Without queued messages there's a related gap: mobile has no way to continue a usage-limited or interrupted run at all, except by typing a new message.

Suggested fix

Bring mobile in line with web:

  1. Move the resumableRunId logic out of ChatView.tsx into client-runtime, so web and mobile share it.
  2. In the mobile handleResumeQueue, when resumableRunId isn't null, send startTurn with manualContinuationOfRunId first, then resumeThreadQueue if runs are still held.
  3. Show the resume action when queueHeld || resumableRunId !== null.
  4. Show the command failure in the thread instead of only logging it.

Impact

A thread that hits a usage limit with a queued message can't be continued from mobile at all, and the user isn't told why.

This hits harder when the limit has no reset time. I run Claude through CLIProxyAPI, a local proxy that spreads requests across several Claude accounts. When every account was cooling down, the proxy returned a plain 429 (All credentials for model claude-opus-5-5 are cooling down), so T3 Code couldn't read a reset time. The stored failure is:

{"class":"usage_limit","message":"Claude API rate limit reached. Try again later.","code":"api_error_429","retryable":true,"resetAt":null}

With resetAt: null, the automatic resume after the limit resets can never schedule, so a manual continue is the only way out. On mobile that path is missing, so the thread stays stuck even after capacity comes back. Here, capacity came back when I added another account to the proxy.

Version or commit

  • Server and runtime: t3 0.1.5 (background service).
  • Mobile: iOS app build 202 (user agent T3Code/202 CFNetwork/3860.700.2 Darwin/25.6.0).
  • The bug is still present on main at dd14848153 (2026-10-29).

Environment

macOS host running the t3 background service. iPhone connected through T3 Connect. Claude provider routed through CLIProxyAPI 8.0.40 (ANTHROPIC_BASE_URL set in the Claude provider's environment), so limit responses carry no reset time.

Logs or stack traces

Server trace spans ws.rpc.orchestration.dispatchCommand → Failure, cause Continue the limited thread before resuming its queue., command type queue.resume. They repeat once per tap, each with a new command id.

Workaround

Continue the thread from the web or desktop client, which sends the manual continuation first. Or remove the queued message, send a fresh message, and queue the rest again.

Activity

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions