openclaw - ✅(Solved) Fix Heartbeat routes to subagent sessions instead of main session [2 pull requests, 8 comments, 4 participants]

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…
GitHub stats
openclaw/openclaw#58878Fetched 2026-04-08 02:31:37
View on GitHub
Comments
8
Participants
4
Timeline
34
Reactions
0
Timeline (top)
referenced ×12commented ×7mentioned ×5subscribed ×5

Fix Action

Fix / Workaround

Workaround: Setting agents.defaults.heartbeat.session: "main" explicitly (even though docs say main is the default).

PR fix notes

PR #61526: fix(agents): heartbeat always targets main session — prevent routing to active subagent sessions

Description (problem / solution / changelog)

Fixes #58878

Summary

  • stop inferring the heartbeat agent/session lane from a forced session key
  • keep heartbeat runs anchored to the configured main agent session even if subagent sessions are active
  • add a regression test proving subagent-scoped session overrides still route heartbeat through agent:main:main

Fixes #58878

Changed files

  • .agents/skills/openclaw-parallels-smoke/SKILL.md (modified, +13/-0)
  • .agents/skills/openclaw-qa-testing/SKILL.md (added, +86/-0)
  • .agents/skills/openclaw-qa-testing/agents/openai.yaml (added, +4/-0)
  • .github/labeler.yml (modified, +4/-0)
  • .github/workflows/ci.yml (modified, +7/-1)
  • .github/workflows/control-ui-locale-refresh.yml (modified, +2/-2)
  • .github/workflows/openclaw-npm-release.yml (modified, +1/-1)
  • CHANGELOG.md (modified, +40/-12)
  • appcast.xml (modified, +248/-116)
  • apps/android/app/build.gradle.kts (modified, +2/-2)
  • apps/ios/Config/Version.xcconfig (modified, +3/-3)
  • apps/macos/Sources/OpenClaw/Resources/Info.plist (modified, +2/-2)
  • apps/macos/Sources/OpenClawProtocol/GatewayModels.swift (modified, +14/-0)
  • apps/shared/OpenClawKit/Sources/OpenClawKit/Resources/tool-display.json (modified, +23/-0)
  • apps/shared/OpenClawKit/Sources/OpenClawProtocol/GatewayModels.swift (modified, +14/-0)
  • docs/.generated/config-baseline.sha256 (modified, +4/-4)
  • docs/.generated/plugin-sdk-api-baseline.sha256 (modified, +2/-2)
  • docs/automation/tasks.md (modified, +5/-0)
  • docs/channels/discord.md (modified, +1/-1)
  • docs/channels/matrix.md (modified, +29/-5)
  • docs/cli/memory.md (modified, +43/-15)
  • docs/cli/update.md (modified, +3/-1)
  • docs/concepts/dreaming.md (modified, +121/-194)
  • docs/concepts/memory-qmd.md (modified, +17/-1)
  • docs/concepts/memory-search.md (modified, +9/-8)
  • docs/concepts/memory.md (modified, +12/-8)
  • docs/concepts/model-providers.md (modified, +2/-0)
  • docs/concepts/models.md (modified, +2/-0)
  • docs/docs.json (modified, +8/-1)
  • docs/gateway/configuration-reference.md (modified, +31/-12)
  • docs/help/faq.md (modified, +36/-0)
  • docs/help/testing.md (modified, +22/-0)
  • docs/install/updating.md (modified, +1/-0)
  • docs/plugins/architecture.md (modified, +1/-0)
  • docs/plugins/building-plugins.md (modified, +1/-0)
  • docs/plugins/manifest.md (modified, +76/-30)
  • docs/plugins/sdk-migration.md (modified, +11/-1)
  • docs/plugins/sdk-overview.md (modified, +22/-9)
  • docs/providers/bedrock-mantle.md (modified, +20/-7)
  • docs/providers/bedrock.md (modified, +29/-0)
  • docs/providers/comfy.md (added, +201/-0)
  • docs/providers/fal.md (modified, +2/-1)
  • docs/providers/google.md (modified, +30/-0)
  • docs/providers/index.md (modified, +4/-0)
  • docs/providers/minimax.md (modified, +29/-0)
  • docs/providers/models.md (modified, +4/-0)
  • docs/providers/openai.md (modified, +10/-2)
  • docs/providers/runway.md (added, +63/-0)
  • docs/providers/vydra.md (added, +123/-0)
  • docs/reference/memory-config.md (modified, +117/-98)
  • docs/tools/image-generation.md (modified, +21/-17)
  • docs/tools/index.md (modified, +14/-7)
  • docs/tools/lobster.md (modified, +11/-9)
  • docs/tools/music-generation.md (added, +208/-0)
  • docs/tools/plugin.md (modified, +1/-0)
  • docs/tools/slash-commands.md (modified, +1/-1)
  • docs/tools/video-generation.md (modified, +147/-84)
  • docs/web/control-ui.md (modified, +4/-1)
  • docs/web/dashboard.md (modified, +2/-0)
  • dream-diary-preview-v2.html (added, +399/-0)
  • dream-diary-preview-v3.html (added, +323/-0)
  • extensions/amazon-bedrock-mantle/api.ts (modified, +2/-0)
  • extensions/amazon-bedrock-mantle/bedrock-token-generator.d.ts (added, +6/-0)
  • extensions/amazon-bedrock-mantle/discovery.test.ts (modified, +101/-3)
  • extensions/amazon-bedrock-mantle/discovery.ts (modified, +64/-13)
  • extensions/amazon-bedrock-mantle/package.json (modified, +3/-0)
  • extensions/bluebubbles/src/accounts.ts (modified, +5/-1)
  • extensions/bluebubbles/src/monitor.ts (modified, +1/-1)
  • extensions/browser/src/browser/chrome.default-browser.test.ts (modified, +2/-6)
  • extensions/browser/src/browser/client-fetch.loopback-auth.test.ts (modified, +2/-6)
  • extensions/browser/src/browser/control-service.plugin-disabled.test.ts (modified, +2/-6)
  • extensions/browser/src/browser/profiles-service.test.ts (modified, +5/-8)
  • extensions/browser/src/browser/pw-tools-core.clamps-timeoutms-scrollintoview.test.ts (modified, +2/-6)
  • extensions/browser/src/browser/pw-tools-core.interactions.batch.test.ts (modified, +2/-6)
  • extensions/browser/src/browser/pw-tools-core.interactions.evaluate.abort.test.ts (modified, +2/-6)
  • extensions/browser/src/browser/pw-tools-core.interactions.set-input-files.test.ts (modified, +2/-4)
  • extensions/browser/src/browser/pw-tools-core.last-file-chooser-arm-wins.test.ts (modified, +2/-6)
  • extensions/browser/src/browser/pw-tools-core.screenshots-element-selector.test.ts (modified, +2/-6)
  • extensions/browser/src/browser/routes/agent.existing-session.test.ts (modified, +3/-8)
  • extensions/browser/src/browser/routes/basic.existing-session.test.ts (modified, +3/-8)
  • extensions/browser/src/browser/server-context.existing-session.test.ts (modified, +3/-8)
  • extensions/browser/src/browser/server-context.hot-reload-profiles.test.ts (modified, +6/-12)
  • extensions/browser/src/browser/server-context.remote-profile-tab-ops.fallback.test.ts (modified, +2/-6)
  • extensions/browser/src/browser/server-context.remote-profile-tab-ops.playwright.test.ts (modified, +2/-6)
  • extensions/browser/src/browser/server-lifecycle.test.ts (modified, +3/-8)
  • extensions/browser/src/browser/server.control-server.test-harness.ts (modified, +2/-1)
  • extensions/browser/src/browser/server.evaluate-disabled-does-not-block-storage.test.ts (modified, +3/-8)
  • extensions/browser/src/cli/browser-cli.test-support.ts (modified, +1/-1)
  • extensions/browser/src/cli/command-format.ts (modified, +1/-1)
  • extensions/browser/src/config/config.ts (modified, +1/-1)
  • extensions/browser/src/core-api.ts (modified, +25/-20)
  • extensions/browser/src/doctor-browser.ts (modified, +1/-1)
  • extensions/browser/src/gateway/auth.ts (modified, +1/-1)
  • extensions/browser/src/gateway/startup-auth.ts (modified, +1/-1)
  • extensions/browser/src/infra/errors.ts (modified, +1/-1)
  • extensions/browser/src/infra/fs-safe.ts (modified, +1/-1)
  • extensions/browser/src/infra/net/proxy-env.ts (modified, +1/-1)
  • extensions/browser/src/infra/net/ssrf.ts (modified, +1/-1)
  • extensions/browser/src/infra/path-guards.ts (modified, +1/-1)
  • extensions/browser/src/infra/ports.ts (modified, +1/-1)

PR #61803: fix(agents): heartbeat always targets main session — prevent routing to active subagent sessions

Description (problem / solution / changelog)

What this fixes (plain English)

When background heartbeat checks ran while sub-agents were active, they could accidentally target a sub-agent's session instead of the main one — corrupting the sub-agent's task results by overwriting them with a heartbeat status. This fix ensures heartbeats always route to the main session.

Technical details

Root cause: resolveHeartbeatSession() had three code paths where a subagent session key could slip through:

  1. Via opts.sessionKey (forced session key)
  2. Via heartbeat.session config value
  3. Via post-canonicalization (where canonicalization transforms a key into a subagent format)

Fix: Added isSubagentSessionKey() guards to all three paths in resolveHeartbeatSession. Any subagent session key is now stripped at every entry point, falling back to mainSessionKey.

Files changed:

  • src/infra/heartbeat-runner.ts — import isSubagentSessionKey, add guards to all three resolution paths, simplify agent ID resolution
  • src/infra/heartbeat-runner.returns-default-unset.test.ts — parameterized regression test covering both entry vectors

Related

  • Fixes #58878
  • Recreated from clean branch (previous PR #61526 closed as dirty)
  • Parent initiative: #25592
  • Companion PRs: #61829, #61463, #61801

Test plan

  • 32/32 tests pass
  • Subagent session keys via opts.sessionKey are rejected -> falls back to mainSessionKey
  • Subagent session keys via heartbeat.session config are rejected -> falls back to mainSessionKey
  • Post-canonicalization subagent keys are rejected
  • Legitimate main session keys still route correctly

Changed files

  • CHANGELOG.md (modified, +1/-1)
  • src/infra/heartbeat-runner.returns-default-unset.test.ts (modified, +92/-0)
RAW_BUFFERClick to expand / collapse

The built-in heartbeat (agents.defaults.heartbeat) is supposed to run in the main session (session: "main" is documented as the default in docs/gateway/heartbeat.md). However, when subagent sessions are active, the heartbeat sometimes routes to a subagent session instead.

Observed behavior:

  • Main session spawns subagents via sessions_spawn
  • Heartbeat fires while subagents are running
  • Heartbeat prompt gets delivered to the subagent session instead of agent:main:main
  • The subagent's origin.provider gets set to "heartbeat"
  • In one session, 6 out of 12 subagent sessions showed origin: "heartbeat" — indicating they received heartbeat routing

Impact:

  • Subagents receive heartbeat prompts they have no context for
  • The subagent's actual task completion gets lost/corrupted
  • Subagent's return value becomes HEARTBEAT_OK instead of its task result

Workaround: Setting agents.defaults.heartbeat.session: "main" explicitly (even though docs say main is the default).

Environment:

  • OpenClaw 2026.3.31
  • Multiple subagents spawned via sessions_spawn API
  • Session keys: agent:main:main (parent), agent:main:subagent:* (children)

extent analysis

TL;DR

Explicitly setting agents.defaults.heartbeat.session to "main" may resolve the issue of heartbeats being routed to subagent sessions instead of the main session.

Guidance

  • Verify that the default session for the heartbeat is indeed set to "main" as per the documentation, and check if this default is being overridden somewhere in the code.
  • Test the workaround of explicitly setting agents.defaults.heartbeat.session to "main" to see if it consistently resolves the issue.
  • Investigate why subagent sessions are receiving heartbeat prompts and how it affects their task completion and return values.
  • Review the sessions_spawn API and its interaction with the heartbeat mechanism to understand how subagent sessions are being spawned and routed.

Example

No explicit code example is provided due to the lack of specific code details in the issue, but the workaround suggests adding or modifying a configuration setting: agents.defaults.heartbeat.session = "main".

Notes

The provided workaround may not be a permanent fix, and the root cause of why the default session is not being respected needs to be investigated. The issue seems to be specific to the interaction between the heartbeat mechanism and subagent sessions spawned via the sessions_spawn API in OpenClaw 2026.3.31.

Recommendation

Apply the workaround by explicitly setting agents.defaults.heartbeat.session to "main", as it has been observed to resolve the issue in the given environment, allowing for further investigation into the root cause without immediate disruption.

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…

Still need to ship something?

×6

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

Back to top recommendations

TRENDING