Skip to content

[Bug]: plugins uninstall can crash with exit 13 when confirmation stdin is closed #73562

@ai-hpc

Description

@ai-hpc

Bug type

Crash (process/app exits or hangs)

Beta release blocker

No

Summary

openclaw plugins uninstall <id> awaits the confirmation prompt through promptYesNo(). When stdin is closed (for example < /dev/null) and --force is not used, Node can exit with Detected unsettled top-level await and code 13 instead of returning a clear CLI error.

Steps to reproduce

  1. Use OpenClaw 2026.4.27 on Node 22.
  2. Ensure the target plugin id is managed by plugin config or install records.
  3. Run pnpm openclaw plugins uninstall <id> < /dev/null.
  4. Observe the uninstall confirmation prompt starts.
  5. Observe Node exits with Detected unsettled top-level await and exit code 13.

Expected behavior

The command should fail cleanly with exit code 1 and an actionable message, for example:

Error: plugins uninstall requires confirmation input. Re-run in an interactive TTY or pass --force.

Piped answers should continue to work:

echo "n" | openclaw plugins uninstall <id>
echo "y" | openclaw plugins uninstall <id>

Non-interactive automation can also use:

openclaw plugins uninstall <id> --force

Actual behavior

With closed stdin, the prompt await can remain unsettled and Node exits with code 13:

Uninstall plugin "<id>"? [y/N] Warning: Detected unsettled top-level await at file:///.../openclaw.mjs:233
  if (await tryImport("./dist/entry.js")) {
      ^

ELIFECYCLE Command failed with exit code 13.

OpenClaw version

2026.4.27 source checkout

Operating system

Ubuntu/Linux

Install method

pnpm dev

Model

N/A

Provider / routing chain

N/A

Additional provider/model setup details

N/A. This is in the CLI prompt path before any provider/model call.

Logs, screenshots, and evidence

The OpenClaw code path is:

  • src/cli/plugins-cli.ts: plugins uninstall calls promptYesNo() when --force is not set.
  • src/cli/prompt.ts: promptYesNo() directly awaits readline.question() and does not handle readline close / EOF.

Minimal Node 22.22.1 reproduction of the dependency behavior:

timeout 10s node --input-type=module -e 'import readline from "node:readline/promises"; const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); const answer = await rl.question("Question? "); console.log("answer", JSON.stringify(answer)); rl.close();' < /dev/null

Observed result:

exit=13
Question? Warning: Detected unsettled top-level await at file:///.../[eval1]:1

Impact and severity

Affected users/systems/channels: anyone running plugins uninstall from CI, scripts, detached shells, or other closed-stdin contexts without --force.

Severity: crash / DX bug. No data corruption observed because the crash happens before config writes.

Frequency: deterministic for the closed-stdin prompt case in the minimal Node/readline reproduction; OpenClaw reaches this prompt path when uninstalling a managed plugin without --force.

Consequence: automation receives exit 13 and an internal Node warning instead of a clear OpenClaw CLI error.

Additional information

Suggested fix: make promptYesNo() EOF-aware by racing readline.question() with readline close, while preserving piped y / n behavior. Then have plugins uninstall catch the closed-input case and exit 1 with a message that suggests --force.

Avoid a simple !process.stdin.isTTY gate because it would break currently working piped answers.

Suggested tests:

  • src/cli/prompt.test.ts: closed readline rejects or returns a distinct closed-input result instead of hanging.
  • src/cli/plugins-cli.uninstall.test.ts: closed confirmation exits 1, does not write config, and suggests --force.
  • Existing --force, cancel, and successful uninstall paths still pass.

Related: #73551 documents the separate stale-entry seed path that can make users try plugins uninstall as cleanup.

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