Skip to content

[Bug]: openclaw tui hangs with stuck spinner and no active run when --deliver is off (default) #66991

@arcabotai

Description

@arcabotai

Summary

On a fresh openclaw tui --session <key> session, sending any message produces a spinner that spins forever. Pressing Esc prints no active run. No assistant reply ever appears in the TUI — yet the backend does run the turn and writes the reply to the session file on disk. Running the same command with --deliver works instantly.

This is a superset of #33102. That (stale) issue covers the ergonomic half — "let me set a default for --deliver in config". This issue is about the harder UX failure: when a user hits today's default, the TUI's run-lifecycle state machine cannot recover, and the product looks broken.

Reproduction

  1. openclaw tui --session smoke-2
  2. Type 2+2
  3. Observed: spinner shows bamboozling... | connected indefinitely.
  4. Press Esc → no active run.
  5. No reply is ever rendered.
  6. openclaw tui --deliver --session smoke-2 → immediately renders 4.
  7. Session file on disk contains the reply — backend answered, it just never streamed to this client.

Confirmed on OpenClaw 2026.4.14 (commit 323493f), macOS (Homebrew), zsh.

Why it's not "just a default"

In dist/tui-*.js:

  • sendMessage sets activityStatus = "waiting" right after client.sendChat(...) resolves.
  • state.activeChatRunId is only set inside handleChatEvent — i.e. when a chat.event frame arrives from the gateway.
  • activityStatus is only cleared inside finalizeRun / lifecycle-end handlers, which also depend on chat.event frames.

When deliver: false is sent on chat.send, the gateway runs the turn to completion but does not stream chat.event frames back to this client. As a result:

  1. activeChatRunId stays null forever → spinner never stops.
  2. abortActive() sees activeChatRunId == null → prints no active run on Esc.
  3. The user's mental model lands on "the TUI is broken", not "the reply was stored but not streamed to me".

And because --deliver defaults to false in cli/tui-cli.ts, every new user hits this on their very first session.

Proposed fix

Four changes:

  1. Flip --deliver default to true in the TUI CLI. Add --no-deliver as the explicit opt-out. (Per commander.js docs: if --deliver is declared first, adding --no-deliver does not change the default — so --deliver remains a harmless no-op for anyone with muscle memory.)
  2. Make deliverDefault mutable at runtime and expose it via state (getter/setter) so a settings toggle can flip it.
  3. In sendMessage, when delivery is off, don't hang — clear pendingOptimisticUserMessage, log a clear system line, and set activityStatus back to idle instead of "waiting".
  4. Add a persistent Deliver replies row to the settings panel, next to Tool output / Show thinking.

Local patch / workaround

I've written a runnable patch script that applies all four changes to an installed 2026.4.14 bundle, along with the full root-cause write-up:

https://github.com/arcabotai/openclaw-tui-deliver-stuck-spinner

git clone https://github.com/arcabotai/openclaw-tui-deliver-stuck-spinner
cd openclaw-tui-deliver-stuck-spinner
node apply-local-patch.mjs

It's idempotent, verifies every old string is present before touching anything, and aborts cleanly on a version mismatch. Happy to open a source-tree PR against this repo if a maintainer wants to pull it in directly.

Environment

  • OpenClaw 2026.4.14 (323493f)
  • macOS (Homebrew), zsh
  • Install path: /opt/homebrew/lib/node_modules/openclaw

Reported by arcabot.ai.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions