Skip to content

OpenClaw release_lane is a no-op when claim is held by a live worker; stuck Telegram inbound events block agent response until gateway restart #95248

Description

@kriegerbangerz-ship-it

Summary

OpenClaw's diagnostic subsystem runs action=release_lane to free stuck lane claims, but the action is a no-op when the claim is held by a live worker process. The result released=0 is logged but no items are actually released. The lane stays guarded indefinitely, blocking subsequent updates and causing silent agent stalls where the agent session appears alive but receives no new messages.

This has been reproduced 3 times in 4 days across different machines, agents, and configurations.

Reproduction

  1. OpenClaw gateway running with a Telegram channel account
  2. Inbound message arrives; gateway worker claims it via a channel_ingress_events row write
  3. The agent runtime stalls on a tool call or runtime operation (not necessarily a config issue — can be transient)
  4. Worker holds the claim indefinitely
  5. Gateway's diagnostic subsystem detects stuck state every ~144 seconds (per gateway log evidence)
  6. release_lane action runs. Logged: released=0. No items released.
  7. Lane stays guarded. Subsequent messages pile up in pending indefinitely.
  8. Agent session remains "active" by heartbeat timestamp but receives nothing
  9. Gateway restart is the only known recovery

Symptoms observed by users

  • Agent session timestamp shows recent activity (heartbeat is recent)
  • Session health metrics look normal (token count, model, runtime state)
  • User sends messages — they appear delivered to Telegram
  • Agent never responds
  • Outbound messages from agent work fine
  • Only restart restores comms
  • Restart "fix" is temporary: gateway reaches the same stall again within minutes-to-hours

Expected behavior

release_lane should actually free the lane when the worker holding the claim is non-responsive:

  • Detect stalled workers (worker thread not making progress for > N seconds)
  • Force-release the stuck claim (mark claim_owner and claim_token as NULL)
  • Mark the associated channel_ingress_events row as failed with reason lane-released-on-stuck
  • Allow subsequent updates to be processed by a fresh claim

Actual behavior

release_lane returns released=0 and the lane stays guarded. The log line released=0 is informational but misleading: it implies the recovery ran, but no work was done.

Reproduction environments

  • OpenClaw: 2026.6.1 (2e08f0f) — affected version
  • Reproduced 3 times:
    • 2026-06-16: Telegram agent on Intel Mac Mini (iWorks-instance deployment)
    • 2026-06-19 22:14 PDT: Main agent on Apple Silicon Mac Mini (Telegram channel:default)
    • 2026-06-19 22:34 PDT: Same Apple Silicon Mac Mini, same agent — recurred within ~10 minutes after gateway restart of fix fix: add @lid format support and allowFrom wildcard handling #1

In all three cases, gateway restart resolved the symptom but the underlying release_lane no-op returned within minutes (or hours) of restart.

Stack trace evidence (2026-06-19 incident, gateway PID 84043)

node::sqlite::StatementSync::Columns
  ↓
columnName (libsqlite3.3.53.1.dylib)
  ↓
_pthread_mutex_firstfit_lock_slow (libsystem_pthread.dylib)
  ↓
_nanov2_free (libsystem_malloc.dylib)
  ↓
_platform_memset

The gateway worker is blocked on a mutex inside malloc while running a SQLite query. Memory footprint at sample time: 664 MB current, 1.2 GB peak — significant allocation churn during the diagnostic timer callbacks.

Hypothesis: the diagnostic timer (run_timersEnvironment::RunTimers → timer callback → release_lane SQL) is blocking on a malloc mutex that another thread is holding. This is consistent with the released=0 symptom: the diagnostic never returns from the SQLite query to actually update the row state.

Log evidence

warn diagnostic stuck session:
  sessionKey=agent:main:telegram:default:direct:<chat_id>
  state=processing age=144s queueDepth=2
  reason=queued_work_without_active_run
  classification=stale_session_state
  recovery=checking

warn diagnostic stuck session recovery:
  age=144s
  action=release_lane
  aborted=false
  drained=true
  released=0

warn diagnostic stuck session recovery outcome:
  status=released
  action=release_lane
  lane=session:agent:main:telegram:default:direct:<chat_id>
  released=0

This pattern recurs every ~144 seconds. released is always 0. The lane never frees.

Database state observed (post-mortem)

Stuck claims look like this in ~/.openclaw/state/openclaw.sqlite:

SELECT event_id, status, attempts, claim_owner, claim_token,
       datetime(claimed_at/1000, 'unixepoch') as claimed,
       CAST((strftime('%s','now') - claimed_at/1000) AS INTEGER) as age_sec,
       last_error
FROM channel_ingress_events
WHERE status='claimed';

-- Result rows look like:
-- 566421515 | claimed | 0 | <gateway_pid>:<uuid> | <uuid> | 22:14:03 | 655 | <null>
-- 566421519 | claimed | 0 | <gateway_pid>:<uuid> | <uuid> | 22:20:20 | 278 | <null>

Note: attempts=0, last_error is null, but claimed_at is hours old. The worker that holds the claim is alive (the gateway process is running, ~38-43% CPU) but the claim is never released or progressed.

Workaround (user-side)

While this bug is open, the workaround is to query SQLite and force-fail the stuck claims:

-- Find stuck claims on a given account
SELECT event_id, status, attempts, claim_owner, claim_token
FROM channel_ingress_events
WHERE status = 'claimed' AND account_id = '<account_id>';

-- Force-fail them
UPDATE channel_ingress_events
SET status = 'failed',
    failed_reason = 'manual-cleanup-stuck-claim',
    failed_at = strftime('%s','now')*1000,
    last_error = 'Stuck claim force-failed to free lane',
    claim_owner = NULL,
    claim_token = NULL
WHERE status = 'claimed' AND account_id = '<account_id>';

Then restart the gateway service:

launchctl bootout gui/$(id -u)/ai.openclaw.gateway
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/ai.openclaw.gateway.plist

Note: this restores comms for hours-to-minutes before recurrence. Not a permanent fix.

Suggested upstream fix

Modify the release_lane action to:

  1. Detect stalled workers: if the claim_owner PID is alive but the claim has not progressed in > N seconds (configurable, suggest 60s default), treat the claim as stalled.
  2. Force-release stalled claims: set claim_owner = NULL, claim_token = NULL, mark the row as failed with failed_reason = 'lane-released-on-stuck'.
  3. Update released count: reflect actual items released, not just the count of claims the action attempted to release.
  4. Add a timeout to the diagnostic timer callback: if the SQLite query or release_lane operation blocks for > 5 seconds, abort the diagnostic cycle with a warning log instead of hanging the gateway worker. This addresses the malloc-mutex blocking we observed in the stack trace.
  5. Investigate WAL-mode + cross-thread lock contention: our evidence shows the gateway worker is blocked on _pthread_mutex_firstfit_lock_slow (macOS malloc subsystem) during a SQLite column lookup. This suggests cross-thread contention within the Node process where one thread is in nanov2_free while another is calling SQLite. Could be related to how the diagnostic timer interacts with the WAL write lock.

Possible relationship to 2026.6.8

Recent 2026.6.8 release notes mention:

  • "stuck-session recovery scheduling no longer resets warning backoff"
  • "fix Telegram rich delivery and ingress recovery"
  • "SQLite avoids WAL on NFS state volumes"

These could be partial fixes to this surface, but the underlying release_lane no-op symptom is not explicitly called out. Could the 2026.6.8 changes be extended or backported to specifically address the release_lane no-op? If 2026.6.8 reproduces this issue, the symptom is still present after the latest stable.

Affected versions

  • Reproduced on: 2026.6.1 (2e08f0f)
  • Possibly affected: 2026.5.x, 2026.4.x (release notes suggest similar SQLite / Telegram ingress surfaces)

Related issues

  • Sub-agent embedded run timeout does not release CommandLane — same symptom class (lane not releasing after timeout), different scope (sub-agent run lane, not channel ingress lane).

Reporter context

  • Reporter: KBzA operations team (Krieger Bangerz Agency)
  • Environment: Mac Mini fleet (Apple Silicon + Intel), Telegram channel accounts
  • User impact: agent comms silently stall; users must recognize the symptom and trigger gateway restart
  • Detection difficulty: high (session health looks normal; only manual SQLite inspection reveals the issue)

Verification steps for maintainers

  1. Spin up a Telegram channel on OpenClaw 2026.6.1 (or 2026.6.8).
  2. Send an inbound message that triggers a tool call the agent can't complete (e.g., missing API key, missing tool permission).
  3. Wait for the agent to stall (typically 60-180 seconds).
  4. Send a new inbound message.
  5. Observe: new message sits in pending, lane stays guarded, release_lane action returns released=0.
  6. Confirm: gateway restart is required to restore comms.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High-priority user-facing bug, regression, or broken workflow.clawsweeper:linked-pr-openClawSweeper found an open linked pull request for this issue.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:crash-loopCrash, hang, restart loop, or process-level availability failure.impact:message-lossChannel message delivery can be lost, duplicated, or misrouted.impact:session-stateSession, memory, transcript, context, or agent state can drift or corrupt.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.

    Type

    No type

    Fields

    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