Skip to content

Rejected promise cached permanently in getConfigSnapshot #83855

@davinci282828

Description

@davinci282828

Severity: high / Confidence: high / Category: bug
Triage: confirmed-bug
Detected against: openclaw v2026.5.18 (latest stable at time of scan, 2026-05-18)
Tooling: clawpatch 0.3.0 + acpx/claude-sonnet-4-5 via Brad Mills protocol (https://x.com/bradmillscan/status/2056377217437909178)

Evidence

  • src/cli/program/config-guard.ts:33-34 (getConfigSnapshot)
configSnapshotPromise ??= readConfigFileSnapshot();
  return configSnapshotPromise;

Reasoning

The ??= operator stores the promise returned by readConfigFileSnapshot() before it settles. If that promise rejects (e.g. due to a transient filesystem error), the rejected promise is permanently stored in the module-level configSnapshotPromise variable. Every subsequent call to getConfigSnapshot() returns the same rejected promise for the lifetime of the process, causing all CLI commands that rely on config validation to fail with the original transient error rather than retrying. The VITEST guard on line 30 bypasses this path for tests, which is why no existing test exercises the failure case.

Reproduction

Simulate a temporary ENOENT on the config file path during the first call to ensureConfigReady, then call a second unrelated command in the same process: the second call will also reject with the same stale error.

Recommendation

Reject the cached promise and clear configSnapshotPromise on failure so the next call retries: configSnapshotPromise = readConfigFileSnapshot(); configSnapshotPromise.catch(() => { configSnapshotPromise = null; });

Why existing tests miss this

The VITEST branch on line 30 always bypasses the cache, so the rejection-caching path is never exercised in the test suite.

Suggested regression test

In a unit test that spies on readConfigFileSnapshot, make the first call reject, call ensureConfigReady twice, and assert the second call also invokes readConfigFileSnapshot again rather than re-throwing the same cached rejection.

Minimum fix scope

Single function getConfigSnapshot in src/cli/program/config-guard.ts


Standardized clawpatch finding submission. Persistent across v2026.5.12 → v2026.5.18 — not resolved by upgrading. Finding ID: fnd_sig-feat-cli-command-0f69ccd6ad-_c445579396.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal backlog priority with limited blast radius.clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.clawsweeper:queueable-fixClawSweeper marked this issue as an existing queue_fix_pr work candidate.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.

    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