Back to News
Tutorial
OpenClaw ACP One‑Shot Run Looks Empty in sessions_history (Even When .jsonl Transcript Exists): What’s Happening and What to Do

OpenClaw ACP One‑Shot Run Looks Empty in sessions_history (Even When .jsonl Transcript Exists): What’s Happening and What to Do

OpenClaw News Editorial

OpenClaw News Editorial

A recent bug report describes a confusing failure mode in OpenClaw’s ACP workflow: an ACP one‑shot run completes normally and writes a full transcript to disk, but sessions_history (and sessions_list(...messageLimit=...)) can briefly return no messages for that same session.

Source issue: openclaw/openclaw#51328

This is particularly risky operationally because it can make a successful run look stuck or empty, triggering unnecessary retries or “ACP is broken” conclusions.

What the symptom looks like

From the report (OpenClaw 2026.3.13, macOS, ACP backend acpx, one‑shot sessions_spawn(runtime="acp", mode="run")):

  • sessions_history(sessionKey, includeTools=true) returned messages: []
  • sessions_list(limit=..., messageLimit=2) showed the session but no recent messages
  • The transcript file ~/.openclaw/agents/<agentId>/sessions/<sessionId>.jsonl already contained:
    • the full user prompt
    • the full assistant completion
    • a normal DONE result

The important detail: this is not the ACP runtime failing to execute. The run completed and the disk transcript exists.

What’s likely happening (and why it’s misleading)

OpenClaw often has a “projection” layer:

  • ACP backends write raw transcripts (.jsonl) as the canonical record
  • session APIs (sessions_history, sessions_list) may read from a processed/loaded representation

When those two layers are temporarily out of sync, you can see an “empty” session via API while the transcript is already on disk.

In practice, this can be caused by:

  • asynchronous ingestion (the transcript is written before the session index is updated)
  • file watcher / polling delays
  • a transient lock / partial-read window during write/close

You don’t need to guess the internal cause to operate safely: you can confirm whether this is “projection lag” in a few minutes.

Fast triage: “empty history” vs “the run never really executed”

The easiest operator mistake here is to treat every “no messages returned” case as the same failure.

A more useful split is:

  • The disk transcript is complete, but the API is temporarily empty
    • that strongly matches the projection / indexing lag described in this article.
  • The disk transcript is also missing the prompt and completion
    • then the investigation should move toward whether the ACP run actually started or failed before producing output.
  • sessions_list can see the session, but recent messages are blank
    • that points more toward a visibility-layer lag than true session absence.
  • It is not limited to one-shot runs, and thread/session modes also keep losing visible messages
    • then do not keep the blame surface limited to ACP one-shot. Expand the check to broader session projection behavior.

This distinction matters because it tells you whether the safest next move is “do not retry yet” or “confirm the run truly executed at all.”

A pragmatic operator checklist

1) Confirm the transcript exists (ground truth)

If sessions_history comes back empty for an ACP run that you believe succeeded:

  1. Locate the transcript:
    • ~/.openclaw/agents/<agentId>/sessions/<sessionId>.jsonl
  2. Verify it contains both the user prompt and assistant completion.

If the file is present and complete, avoid re-running the job immediately—you may duplicate work or duplicate side effects (commits, deployments, messages).

2) Re-check the API after a short delay

Because the report describes timing-sensitive behavior (“shortly after spawn”), do a timed re-check:

  • wait 15–60 seconds
  • call sessions_history(..., includeTools=true) again

If messages appear later, this strongly supports a projection/ingestion lag rather than true loss.

3) If it stays empty: collect evidence that helps maintainers fix it

Before you restart anything, gather a small, high-signal bundle:

  • the exact ACP spawn parameters (runtime, agentId, mode, and any resume/session id)
  • the sessionKey you used
  • the first ~50 lines and last ~50 lines of the .jsonl transcript (redact secrets)
  • the API outputs of:
    • sessions_history(sessionKey, includeTools=true)
    • sessions_list(limit=..., messageLimit=2)

This makes it much easier to confirm whether the session API is reading the wrong source, missing an index update, or failing on a parse boundary.

4) Operational mitigation: treat disk transcript as authoritative for “did it run?”

Until this is fixed, for ACP one‑shot runs you may want to adjust your runbook:

  • If .jsonl exists and contains a DONE completion, treat the run as completed, even if sessions_history is empty.
  • For automated orchestration, prefer idempotent actions and avoid “retry on empty history” logic without a delay and a disk check.

Why this matters for production-like usage

ACP one‑shot runs are commonly used for “do X and exit” tasks (e.g., coding, patching, report generation). A false “empty session” signal can:

  • cause duplicate executions
  • create conflicting commits
  • burn unnecessary model budget
  • confuse operators who depend on sessions_list for quick health checks

Common rollout questions

When should you stop blaming the ACP agent and suspect session projection lag instead

If the transcript .jsonl already contains a complete prompt, a complete completion, and a normal DONE marker, but sessions_history still returns messages: [], that is the moment to stop treating it as an “agent failed to run” problem. At that point the safer working theory is projection lag or index lag between disk state and session APIs.

What is the safest way to avoid duplicate side effects while this bug still exists

Add a two-step guard before any retry: wait briefly, then check whether the transcript on disk already shows a completed run. If it does, do not auto-rerun side-effecting work such as commits, deploys, or outbound messages unless a human explicitly decides the first run should be repeated.

If GA4 brings you here from troubleshooting, split transcript evidence from API projection

This page now appears in the same GA4 window as the troubleshooting hub and setup traffic. Treat that as a high-intent operator path: the reader is probably not browsing a release note, they are trying to decide whether an ACP run is lost, delayed, or just hidden behind a stale session API view.

Use this three-way split before escalating the incident:

  1. No transcript file exists: debug launch, permissions, sandbox paths, and runtime startup first. This is not an empty-history projection problem yet.
  2. Transcript exists but sessions_history is empty: preserve the .jsonl, session id, runtime, and timestamps, then continue work from the transcript while treating the API as stale.
  3. Transcript and API disagree across multiple checks: move the case into the troubleshooting hub and compare it with session timeout or Gateway-state symptoms before restarting production automation.

That routing keeps the page useful for operators who arrive from generic troubleshooting searches and need a fast “lost run vs stale API” decision.

Related reading

FAQ for search and projection-lag triage

If the .jsonl transcript already contains a full completion but sessions_history is still empty, what should operators assume first?

They should not assume the run failed and immediately retry it.

The safer first assumption is session projection lag, because this failure mode is specifically dangerous when:

  • the real execution already finished
  • the transcript already exists on disk
  • but the API view has not surfaced the result yet

Immediate retries are exactly how teams turn a visibility bug into duplicate side effects.

When should this be treated as an indexing or visibility-layer delay rather than an ACP agent failure?

If all of these are true together:

  1. sessions_list can still see the session
  2. the .jsonl already contains both prompt and completion
  3. only sessions_history or recent messages remain empty

then indexing or visibility lag is the better first theory than “the ACP agent never ran”.

If someone searches for sessions_history empty but jsonl exists, what are the first three branches this page should help them split?

Help them separate these first:

  1. whether the disk transcript is already complete
  2. whether the empty API view happens only shortly after spawn or still persists much later
  3. whether only one-shot runs are affected or thread/session modes also lose visibility

Those three checks are the fastest route from “the task probably never ran” to “the session API is lagging behind the transcript state”.

Minimum handoff packet for the next operator

The worst handoff for this bug is a single line saying “history is empty.” The next operator may assume the run never happened and trigger duplicate work. Leave at least five pieces of evidence:

  1. the sessionKey, agentId, runtime, and mode, so nobody investigates the wrong session;
  2. the .jsonl transcript path, plus a redacted snippet from both the start and end of the file;
  3. the raw sessions_history(..., includeTools=true) response, preserving whether it returned an empty array or missed fields;
  4. the sessions_list(..., messageLimit=2) response, to compare list-summary visibility with history visibility;
  5. whether any side-effecting action already ran, such as commit, push, deploy, outbound message, or external API write.

With that packet, the next step can move from “maybe the task never ran” to “which layer is out of sync: disk completion, history projection, or list summary.” That is safer than retrying and much better suited for production runbooks.

Run four closeout checks before calling it recovered

When sessions_history eventually shows messages, do not close the incident immediately. Add four closeout checks first:

  1. Re-check the same sessionKey: confirm the recovered view belongs to the original session, not a later rerun.
  2. Align list and history: compare sessions_list(...messageLimit=2) with sessions_history(...includeTools=true) and verify both views show the same message set.
  3. Tool-message visibility: if the run used tools, confirm tool calls and tool results are visible through the API, not only in .jsonl.
  4. No duplicated side effects: check commits, pushes, deployments, outbound messages, or external API writes to ensure the empty history did not trigger a second execution.

These closeout checks turn “the page is no longer empty” into handoff-grade recovery evidence, and serve operators searching for sessions_list messageLimit empty or ACP transcript exists history empty.

Evidence checklist before you trust an empty session API response

When a transcript exists but the session API returns an empty history, treat the API response as one projection view, not the source of truth. Before escalating or rebuilding the session, capture these checks:

  1. Transcript path and timestamp: record the local transcript file, its last write time, and the message IDs or turns that prove the run happened.
  2. API endpoint and caller context: note whether the empty response came from sessions_history, a dashboard projection, or another wrapper.
  3. Session identity mapping: compare the visible session key, ACP session id, and any persisted run id so you can spot a projection mismatch.
  4. Freshness window: recheck after a short delay, then decide whether this is a projection lag, a wrong session lookup, or a real ingestion failure.

This keeps operators from deleting useful transcripts just because one API view is temporarily empty.

Search-entry triage: what to check when transcript exists but session APIs return empty history

If you landed here from searches like “ACP transcript exists but history empty”, “session API returns empty history”, or “OpenClaw cannot read session history”, split the issue into four layers:

  1. Check whether transcript and session APIs read the same source: a local transcript file can exist while the API is querying a different session id, workspace, or run scope.
  2. Check the history read window: some APIs filter by active session, thread, agent runtime, or resume id, which can make a populated file look like an empty history response.
  3. Check write and indexing timing: crash recovery, restarts, background subagent completion, and flush delays can put transcript on disk before the session index updates.
  4. Preserve three proofs: transcript path, session API request parameters, and the empty history response are more useful than only a screenshot saying “history is missing”.

Do not debug this class of issue only by refreshing the UI. The shortest path is to compare transcript file, session identifiers, API filters, and index-refresh timing.

Related reading

When empty history should block automation

Most empty-history incidents should slow a runbook down, not stop every operator. Block automation only when the missing history can hide irreversible side effects. Use this rule before allowing a cron job, deploy bot, or retry loop to continue:

  1. Block immediately if the previous run may have committed, pushed, deployed, sent an external message, charged a customer, or wrote to a third-party API.
  2. Allow read-only continuation if the next step only collects transcript paths, session ids, logs, or public page status.
  3. Require a human checkpoint when the transcript proves completion but the API view is empty and the next planned step would repeat the same side effect.
  4. Resume automation only after the transcript, sessions_list, and sessions_history agree on the original run or after the duplicate-side-effect check is complete.

This gives search visitors a safer answer to sessions_history empty retry or wait: wait for evidence before repeating side-effecting work, but keep read-only diagnosis moving.

When to file it as a platform bug instead of waiting

Do not wait indefinitely once the transcript proves the run completed. Escalate it as a platform bug when all four signals line up:

  1. the .jsonl transcript has the missing turns, including the final assistant or tool result;
  2. sessions_history(..., includeTools=true) still returns empty or incomplete data after a second read;
  3. sessions_list(..., messageLimit=2) also misses the same messages, or shows a different session key;
  4. the next automation step would repeat a commit, deploy, external message, or third-party write.

In that case, the safest operator move is to attach the transcript path, raw API responses, session key, runtime, and a duplicate-side-effect check to the bug report. That packet helps maintainers separate projection lag from a wrong-session lookup, and it gives search visitors a concrete escalation threshold instead of a vague "try again later" answer.

Safe retry policy for cron jobs and deploy bots

For automated operators, the question is not only whether history is empty. The higher-risk question is whether a retry could repeat a side effect that already happened in the transcript. Use this retry policy before a scheduled job, deploy bot, or monitoring loop continues.

Retry only read-only checks while the transcript and API disagree. Do not rerun commits, pushes, deploys, outbound messages, paid API calls, or document writes until you have compared the transcript tail, sessions_list, and sessions_history for the original session key. If those views still disagree, move the job into manual review instead of letting the scheduler create a second production action.

This gives search traffic for empty session history retry policy, ACP transcript exists should I rerun, and sessions_history empty cron job a practical answer: keep diagnosis moving, but freeze duplicate side effects until execution state and projection state agree.

Source

Three-minute split after search: lost run, stale API, or wrong session

If you arrived by searching sessions_history empty, jsonl exists, or ACP transcript empty history, do not rerun the task first. Spend three minutes routing the risk to the right layer:

  1. There is no .jsonl file or the file is empty: inspect ACP launch, working directory, permissions, and sandbox mounts first. This is not an API projection issue yet.
  2. The .jsonl already contains both prompt and completion, but the API is empty: treat the disk transcript as the temporary source of truth, pause automatic retries, and capture session id, timestamps, and the raw API response.
  3. sessions_list sees the session but sessions_history shows no messages: suspect summary/history projection drift before blaming the agent execution.
  4. Different session keys return different results: align the visible session key, ACP session id, and persisted run id before calling it lost history.

This moves high-intent troubleshooting traffic from “it looks like the run never happened” to “which layer disagrees: execution state, projected API view, or session identity mapping,” reducing duplicate commits, deployments, or external writes.

© 2025 OpenClawNews.org
All rights reserved.
This is an independent news site. Not affiliated with, endorsed by, or connected to OpenClaw. OpenClaw is a trademark of its respective owner.
Join the waitlist:

OC NEWS