Skip to content

[Bug]: Preflight compaction throws on a successful no-op compactor result (ok:true, compacted:false) — bricks every message on long sessions #87075

Description

@PSedd

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

No

Summary

Core's preflight compaction treats a successful no-op compactor result (ok: true, compacted: false, reason already under target) as a fatal error and throws, so every subsequent message to a large session fails to dispatch until /new.

Steps to reproduce

  1. Run a session with a token-based compaction provider (here: lossless-claw @martian-engineering/lossless-claw 0.11.2) and agents.defaults.compaction.mode: default.
  2. Let the session's persisted transcript grow until core's preflight token threshold trips while the provider's live (already-summarized) context stays under target.
  3. Send any message.

Observed on a session whose persisted transcript had grown to ~2 MB; the error then repeats on every message until /new resets the session.

Expected behavior

A successful compactor result with nothing left to compact (ok: true, compacted: false, e.g. reason already under target) should be treated as a benign no-op and message dispatch should proceed — matching the same function's existing "no compaction needed" early return. A fresh/small session in the identical setup dispatches normally.

Actual behavior

Message dispatch errors and no reply is produced. Gateway log (repeats on every message to the session):

[diagnostic] message dispatch completed: channel=webchat sessionKey=agent:main:main source=replyResolver outcome=error duration=9270ms error="Error: Preflight compaction required but failed: already under target"

The session is unusable until /new. To the user it surfaces as a generic dispatch failure.

OpenClaw version

2026.5.22 (a374c3a)

Operating system

Ubuntu 25.10, Linux 6.17.0-29-generic (x86_64)

Install method

npm global install (~/.npm-global/lib/node_modules/openclaw); gateway run as a systemd service

Model

anthropic/claude-opus-4-7 (claude-cli backend)

Provider / routing chain

claude-cli backend (provider=claude-cli). Compaction provider: lossless-claw (@martian-engineering/lossless-claw) 0.11.2 as the active compaction extension.

Additional provider/model setup details

agents.defaults.compaction.mode: default. truncateAfterCompaction unset and maxActiveTranscriptBytes unset, so the transcript-byte trigger is disabled — this fires on the token trigger path. No API keys/tokens/passwords included.

Logs, screenshots, and evidence

**Gateway log** (every message):

error="Error: Preflight compaction required but failed: already under target"


**Core**`dist/agent-runner.runtime-*.js`, preflight compaction block (decides "required" from `freshPersistedTokens`, i.e. the persisted transcript):

const result = await memoryDeps.compactEmbeddedPiSession({ /* trigger: "budget", currentTokenCount: tokenCountForCompaction ?? freshPersistedTokens, ... */ });
if (!result?.ok || !result.compacted) {            // only inspects .compacted
    const reason = result?.reason ?? "not_compacted";
    throw new Error(`Preflight compaction required but failed: ${reason}`);
}


**Provider** — lossless-claw `dist/index.js`, `compactUntilUnder` result mapping (measures the live/already-summarized context, finds it under target, returns success with zero rounds):

const didCompact = compactResult.rounds > 0;
const compactUntilReason = /* ... */ compactResult.success
    ? (didCompact ? "compacted" : "already under target")   // success=true, rounds=0
    : "could not reach target";

So the provider returns `ok:true, compacted:false, reason:"already under target"` — a legitimate "nothing to do". Core ignores `result.ok` and throws on `!result.compacted`.

Ruled out: not OOM (`dmesg` clean, swap 0 B used); unrelated to the claude-cli harness-registration path.

Impact and severity

  • Affected: any session large enough that core's preflight gate keeps firing while the compaction provider reports nothing to compact (reproduced with lossless-claw; any provider returning a valid "nothing to compact" success hits the same code path).
  • Severity: blocks workflow / message loss — every message to the affected session fails to dispatch.
  • Frequency: deterministic once a session crosses the threshold; persists until /new.
  • Consequence: the session is effectively bricked; the user must start a new session and lose continuity.

Additional information

Suggested fix — treat a successful "nothing to compact" result as a benign no-op and proceed, mirroring the function's existing "no compaction needed" early return:

if (!result?.ok || !result.compacted) {
    const reason = result?.reason ?? "not_compacted";
    if (result?.ok && (reason === "already under target" || reason === "nothing to compact")) {
        return entry ?? params.sessionEntry; // proceed; provider already feeds the model its compacted context
    }
    throw new Error(`Preflight compaction required but failed: ${reason}`);
}

Optionally also align the token source core uses for the preflight trigger with the provider's live measurement so the two stop diverging.

Related (not duplicates): #60858 (guards silently block compaction — different mechanism); #68930, #61864, #65600 (preflight/token-propagation issues in the same subsystem, all closed; none covers throwing on ok:true, compacted:false).

Note: the bundled file's hash suffix (agent-runner.runtime-*.js) changes per release; locate by grepping Preflight compaction required but failed. A local patch applying the guard above resolved a session that reproduced this on every message.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High-priority user-facing bug, regression, or broken workflow.bugSomething isn't workingbug:behaviorIncorrect behavior without a crashimpact:message-lossChannel message delivery can be lost, duplicated, or misrouted.impact:session-stateSession, memory, transcript, context, or agent state can drift or corrupt.

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions