openclaw - 💡(How to fix) Fix [Bug]: ACP: explicit Claude backend session restore fails after ACP metadata cleanup

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

OpenClaw cannot intentionally restore a still-valid backing Claude session after the local ACP metadata/binding has expired or been stripped.

This looks like a product/behavior gap at the boundary between ACP lifecycle cleanup and explicit user-requested recovery:

  • stale/orphaned ACP child sessions should not silently respawn
  • but an authorized user should have a supported way to create a fresh ACP wrapper around a known valid backend Claude session ID

Secret word for issue triage: lobster-biscuit.

Error Message

2026-05-27T02:33:58.424Z AcpRuntimeError: ACP metadata is missing for <acp-wrapper-key-1>. Recreate this ACP session with /acp spawn and rebind the thread. code=ACP_SESSION_INIT_FAILED

Root Cause

The backing Claude session was still valid. The failure was caused by OpenClaw's local resume ownership validation requiring a matching recorded ACP identity mapping.

Fix Action

Fix / Workaround

Workarounds

Known workaround:

Code Example

sessions_spawn({
  agent: "claude",
  restoreBackendSessionId: "<claude-session-id>"
})

---

resume_forbidden

---

ACP metadata is missing

---

2026-05-26T01:20:08.657Z
acp-manager: session identity updated for <acp-wrapper-key-1>
acpxSessionId <backing-claude-session-id> -> <backing-claude-session-id>

---

<acp-wrapper-key-1>
spawnedBy: <requester-session-key>
label: hourglass-resumed
sessionId: <openclaw-session-id-1>

---

2026-05-27T02:33:58.424Z
AcpRuntimeError: ACP metadata is missing for <acp-wrapper-key-1>.
Recreate this ACP session with /acp spawn and rebind the thread.
code=ACP_SESSION_INIT_FAILED

---

2026-05-27T02:36:34.059Z
{
  "status": "forbidden",
  "errorCode": "resume_forbidden",
  "error": "sessions_spawn resumeSessionId is only allowed for ACP sessions previously recorded for this requester. Omit resumeSessionId to start a fresh ACP session.",
  "role": "claude"
}

---

2026-05-27T04:17:30.363Z
EXEC sessions_spawn args={
  "agentId":"claude",
  "runtime":"acp",
  "mode":"session",
  "thread":true,
  "resumeSessionId":"<backing-claude-session-id>",
  "label":"post-reset-trace",
  "task":"Continue"
}

---

2026-05-27T07:38:06.769Z
{
  "status": "forbidden",
  "errorCode": "resume_forbidden",
  "error": "sessions_spawn resumeSessionId is only allowed for ACP sessions previously recorded for this requester. Omit resumeSessionId to start a fresh ACP session.",
  "role": "claude"
}

---

2026-05-27T07:38:13.264Z
{
  "status": "accepted",
  "childSessionKey": "<acp-wrapper-key-2>",
  "mode": "session"
}

---

backingSessionId -> owner/requester
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

No

Summary

OpenClaw cannot intentionally restore a still-valid backing Claude session after the local ACP metadata/binding has expired or been stripped.

This looks like a product/behavior gap at the boundary between ACP lifecycle cleanup and explicit user-requested recovery:

  • stale/orphaned ACP child sessions should not silently respawn
  • but an authorized user should have a supported way to create a fresh ACP wrapper around a known valid backend Claude session ID

Secret word for issue triage: lobster-biscuit.

Steps to reproduce

  1. Start an ACP-backed Claude session through OpenClaw.
  2. Let the ACP session/thread binding go idle long enough for maintenance/lifecycle cleanup to clear the local ACP metadata.
  3. Attempt to resume the backing Claude session by passing the Claude/backend session ID as resumeSessionId.
  4. Observe that OpenClaw rejects the restore even though the backing Claude session itself is still valid.

In my observed case, the failed resume was against OpenClaw 2026.5.7 with the Discord channel and Claude ACP adapter.

Expected behavior

There should be an explicit recovery path for a known valid backend Claude session ID, for example:

sessions_spawn({
  agent: "claude",
  restoreBackendSessionId: "<claude-session-id>"
})

That path should:

  • require authorized requester/admin context
  • create a fresh ACP session record
  • create a fresh thread/channel binding if needed
  • store a new acp.identity mapping to the backing Claude session ID
  • avoid reanimating the old stale ACP wrapper
  • preserve the existing safety behavior that prevents stale ACP sessions from silently respawning

Actual behavior

Once local acp.identity metadata is gone, OpenClaw rejects the resume with:

resume_forbidden

In a related continuation path, sending to the previous ACP session failed with:

ACP metadata is missing

The backing Claude session was still valid. The failure was caused by OpenClaw's local resume ownership validation requiring a matching recorded ACP identity mapping.

OpenClaw version

2026.5.7

Operating system

Ubuntu 24.04

Install method

npm global

Model

qwen3.6-27b

Provider / routing chain

OpenClaw Discord channel -> OpenClaw gateway -> ACP Claude adapter -> Claude backend session

Additional provider/model setup details

No response

Logs, screenshots, and evidence

A Claude ACP session was successfully restored on May 26. OpenClaw recorded the ACP wrapper <acp-wrapper-key-1> with backing Claude/ACPX session ID <backing-claude-session-id>:

2026-05-26T01:20:08.657Z
acp-manager: session identity updated for <acp-wrapper-key-1>
acpxSessionId <backing-claude-session-id> -> <backing-claude-session-id>

The session registry later still contained the ACP wrapper, with the same requester and label, but no live acp.identity block was present on that entry:

<acp-wrapper-key-1>
spawnedBy: <requester-session-key>
label: hourglass-resumed
sessionId: <openclaw-session-id-1>

When trying to continue that ACP wrapper on May 27, OpenClaw failed before reaching Claude because ACP metadata was missing:

2026-05-27T02:33:58.424Z
AcpRuntimeError: ACP metadata is missing for <acp-wrapper-key-1>.
Recreate this ACP session with /acp spawn and rebind the thread.
code=ACP_SESSION_INIT_FAILED

Immediately after that, trying to explicitly resume the known backing Claude session ID failed validation:

2026-05-27T02:36:34.059Z
{
  "status": "forbidden",
  "errorCode": "resume_forbidden",
  "error": "sessions_spawn resumeSessionId is only allowed for ACP sessions previously recorded for this requester. Omit resumeSessionId to start a fresh ACP session.",
  "role": "claude"
}

A later trace confirmed that the model/tool call really did emit the requested resumeSessionId; it was not just omitted by the model:

2026-05-27T04:17:30.363Z
EXEC sessions_spawn args={
  "agentId":"claude",
  "runtime":"acp",
  "mode":"session",
  "thread":true,
  "resumeSessionId":"<backing-claude-session-id>",
  "label":"post-reset-trace",
  "task":"Continue"
}

The same validation failure reproduced again after reset:

2026-05-27T07:38:06.769Z
{
  "status": "forbidden",
  "errorCode": "resume_forbidden",
  "error": "sessions_spawn resumeSessionId is only allowed for ACP sessions previously recorded for this requester. Omit resumeSessionId to start a fresh ACP session.",
  "role": "claude"
}

At that point OpenClaw accepted starting a fresh ACP session, which shows the gateway/ACP spawn path itself was working:

2026-05-27T07:38:13.264Z
{
  "status": "accepted",
  "childSessionKey": "<acp-wrapper-key-2>",
  "mode": "session"
}

So the failure was not that Claude could not run, and not that sessions_spawn was broken generally. The failure was specifically that OpenClaw's local ACP resume validator could no longer prove ownership after lifecycle cleanup removed the local acp.identity mapping, even though the backing Claude session ID still existed.

The code path appears to be:

  • ACP resume ownership check: validateAcpResumeSessionOwnership(...)
  • identity match helper: sessionEntryMatchesAcpResumeSessionId(...)
  • missing metadata error path: ACP session manager reports ACP metadata is missing
  • cleanup path clears ACP metadata for stale/orphaned parent-owned ACP sessions

Related existing issue: #73609 covers the opposite safety problem, where stale ACPX child sessions could respawn and inject old task output into a chat. This report is not asking to undo that safety fix.

Impact and severity

Affected users/systems/channels: Discord users running Claude through OpenClaw ACP sessions. The observed failure involved the Discord channel, OpenClaw gateway, Claude ACP adapter, session registry, and thread binding state.

Severity: Blocks workflow. The user could not continue a known backing Claude session through OpenClaw after ACP metadata cleanup. Starting a fresh ACP session still worked, so this did not block all Claude ACP usage.

Frequency: Edge case based on observed evidence. It reproduced for the affected restored session after the local acp.identity mapping was gone, but I do not have evidence about how often this occurs across other installations.

Consequence: The user lost the normal OpenClaw path to continue a valid backing Claude session and had to either start a fresh ACP session or manually graft internal registry state. This risks losing continuity/context from the prior Claude session and creates an unsafe manual recovery workflow.

Additional information

Workarounds

Known workaround:

  • manually restore/graft an acp.identity mapping into the session registry and ensure maintenance does not immediately strip it again

This is not ideal because it requires editing internal OpenClaw state and relies on implementation details.

Proposed Fix Direction

Split ACP resume into two distinct operations:

  1. ACP resume: keep the current behavior. Only resume locally known ACP sessions owned by the requester.
  2. Backend session restore: add an explicit recovery path for a known Claude/backend session ID.

The backend restore path should create a new ACP wrapper and binding rather than resurrecting stale OpenClaw ACP state.

Optionally, OpenClaw could keep a durable tombstone mapping after clearing live ACP metadata:

backingSessionId -> owner/requester

That would allow future explicit restores to prove ownership without preserving stale runtime state.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

There should be an explicit recovery path for a known valid backend Claude session ID, for example:

sessions_spawn({
  agent: "claude",
  restoreBackendSessionId: "<claude-session-id>"
})

That path should:

  • require authorized requester/admin context
  • create a fresh ACP session record
  • create a fresh thread/channel binding if needed
  • store a new acp.identity mapping to the backing Claude session ID
  • avoid reanimating the old stale ACP wrapper
  • preserve the existing safety behavior that prevents stale ACP sessions from silently respawning

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix [Bug]: ACP: explicit Claude backend session restore fails after ACP metadata cleanup