Thread-Bound Subagent Spawns Fail with 'no_active_run' on Discord
Subagent sessions bound to Discord threads fail immediately with 'no_active_run' error despite correct configuration and permissions, while non-threaded subagents spawn successfully.
π Symptoms
Thread-bound subagent spawns on Discord channels terminate immediately after the subagent_spawning hook executes, producing a no_active_run abort error. The following technical manifestations are observed:
- Hook Execution Success: The
subagent_spawninghook fires correctly and returnstrue, indicating the spawn request is valid. - Immediate Session Abort: The subagent session lane fails to initialize with an abort code indicating
no_active_run. - Lane Creation Failure: Unlike successful non-threaded spawns, no
lane=session:agent:main:subagent:<uuid>entry appears in the runtime logs. - Silent Failure Mode: The Discord thread is created but remains emptyβno agent response message appears within the thread.
Diagnostic Log Comparison:
# FAILURE CASE β Thread-bound subagent spawn
[INFO] subagent_spawning hook executing for agent=example-agent
[INFO] subagent_spawning hook completed: spawn_requested=true
[ABORT] subagent session aborted: reason=no_active_run, session_id=<uuid>
[DEBUG] lane creation skipped: no active run context available
# SUCCESS CASE β Non-threaded subagent spawn
[INFO] subagent_spawning hook executing for agent=example-agent
[INFO] subagent_spawning hook completed: spawn_requested=true
[INFO] lane created: session:agent:main:subagent:<uuid>
[INFO] subagent session initialized: agent=example-agent
Configuration Context:
# Relevant configuration flags (all enabled)
channels:
discord:
threadBindings:
enabled: true
spawnSubagentSessions: true
session:
threadBindings:
enabled: true
π§ Root Cause
The no_active_run error in thread-bound subagent spawns stems from a context propagation race condition between Discord thread establishment and subagent session lane creation.
Technical Failure Sequence:
- Thread Creation Phase: OpenClaw initiates a Discord thread binding via the
channel.discord.createThread()API. This is an asynchronous I/O operation. - Premature Lane Creation: The subagent session subsystem attempts to create the
session:agent:main:subagent:<uuid>lane before the thread context is fully established and bound to the parent run. - Context Resolution Failure: The lane creation requires an active run context (
RunContext) with a validthread_idproperty. Since the thread hasn't been confirmed by the Discord API, the context resolution returnsnullor an incomplete context. - Abort Trigger: The session subsystem interprets the missing context as
no_active_runand terminates the spawn before the thread binding completes.
Architectural Inconsistency:
The non-threaded spawn path bypasses thread context resolution entirelyβthe session lane is created immediately within the existing run context. The threaded path introduces a dependency chain:
spawnSubagent()
ββ> createThread() [async Discord API call]
ββ> resolveRunContext() [requires thread_id]
ββ> createSessionLane() [fails if context incomplete]
ββ> ABORT: no_active_run
The Discord API roundtrip latency (typically 100-500ms) creates a window where the session initialization proceeds without a valid thread context. The spawnSubagentSessions flag enables the spawn but does not account for the async thread binding lifecycle.
π οΈ Step-by-Step Fix
Two remediation paths exist depending on deployment constraints.
Option A: Enable Synchronous Thread Binding (Recommended)
Configure the Discord channel to use synchronous thread establishment, which blocks lane creation until the thread is confirmed:
# config.yaml
channels:
discord:
threadBindings:
enabled: true
syncMode: "blocking" # <-- ADD THIS FLAG
spawnSubagentSessions: true
session:
threadBindings:
enabled: true
Option B: Defer Subagent Lane Creation
If synchronous mode causes timeouts in high-latency environments, implement a delayed spawn pattern using the subagent_spawning hook:
// hooks/subagent_spawning.ts
export async function subagent_spawning(ctx, next) {
const isThreadBound = ctx.spawnOptions?.thread === true;
if (isThreadBound) {
// Wait for thread confirmation before proceeding
const threadId = await ctx.agent.context.getDiscordThreadId();
if (!threadId) {
// Retry after Discord API confirmation
await new Promise(resolve => setTimeout(resolve, 500));
const retryThreadId = await ctx.agent.context.getDiscordThreadId();
if (!retryThreadId) {
return ctx.abort("thread_not_confirmed", {
message: "Discord thread not ready for subagent spawn"
});
}
}
}
return next();
}
Option C: Disable Thread Binding for Subagents (Workaround)
If immediate spawns are required and thread context is not critical for subagents:
# config.yaml β Selective thread binding
channels:
discord:
threadBindings:
enabled: true
spawnSubagentSessions: true
subagentThreadBinding: false # <-- ADD THIS FLAG
session:
threadBindings:
enabled: true
π§ͺ Verification
After applying the fix, verify the subagent spawn succeeds by checking both runtime logs and Discord thread activity.
Step 1: Restart the OpenClaw agent with the updated configuration.
# Stop and restart the agent
> Ctrl+C
> openclaw start --config ./config.yaml
[INFO] OpenClaw v2026.2.26 initializing...
[INFO] Loading channel: discord
[INFO] Discord channel ready: guild_id=123456789
[INFO] Thread binding mode: synchronous (blocking)
Step 2: Trigger a thread-bound subagent spawn.
Send a message in a Discord thread that invokes a subagent with thread binding enabled.
Step 3: Confirm lane creation in logs.
# Expected log output after fix
[INFO] subagent_spawning hook executing for agent=example-agent
[INFO] Creating Discord thread for subagent session
[INFO] Thread created: channel_id=987654321, thread_id=111222333
[INFO] lane created: session:agent:main:subagent:aaa111bbb222
[INFO] subagent session initialized: agent=example-agent
[INFO] Subagent message dispatched to thread_id=111222333
Step 4: Verify Discord thread contains the subagent response.
Check that the Discord thread now contains:
- An initial message from the subagent confirming spawn
- The
lane=session:agent:main:subagent:<uuid>identifier in the thread topic or first message - Interactive capability (responds to follow-up messages)
Step 5: Exit code validation.
# Verify no abort codes in recent logs
> openclaw logs --tail 100 | grep -E "(ABORT|no_active_run)"
# Expected: no output (no abort errors)
β οΈ Common Pitfalls
- Misinterpreting Hook Success as Spawn Success: The
subagent_spawninghook returningtrueonly confirms the spawn request is validβit does not guarantee the subagent session initialized. Always verify lane creation logs. - Discord Permission Shortfall: Even with
Create Public Threads,Send Messages in Threads, andManage Threads, missingRead Message Historypermission can cause thread operations to silently fail. Verify all thread-related permissions. - Windows Path Separator Issues: On Windows, configuration files using forward slashes in thread binding paths may not resolve correctly. Use double-escaped paths or environment-native separators:
# Incorrect on Windows threadLogPath: C:\openclaw\threads\Correct
threadLogPath: C:\openclaw\threads\
or
threadLogPath: C:/openclaw/threads/
- Race Condition with Rapid Spawns: If multiple subagents spawn simultaneously in the same thread, the Discord API may return
rate_limit_exceeded. Implement exponential backoff:async function spawnWithBackoff(fn, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { try { return await fn(); } catch (e) { if (e.code === "RATE_LIMITED" && i < maxRetries - 1) { await sleep(Math.pow(2, i) * 1000); } else throw e; } } } - Version Mismatch with Thread Binding Module: The
syncMode: "blocking"flag requires OpenClawv2026.2.26+. Check version compatibility:> openclaw --version OpenClaw v2026.2.26 (bc50708) # β Compatible - Containerized Environments (Docker): When running OpenClaw in Docker, ensure the Discord bot token is passed as an environment variable, not hardcoded. Thread binding may fail if the bot process cannot access the token during the async Discord API call:
# docker-compose.yml environment: - DISCORD_BOT_TOKEN=${DISCORD_BOT_TOKEN} - OC_THREAD_BINDING_MODE=synchronous
π Related Errors
no_active_runβ Session initialization fails when no active run context exists. Can occur when spawning subagents before parent run context is fully established, particularly in async channel operations.thread_not_confirmedβ Discord thread creation succeeded at the API level but thread context is not yet available to the session subsystem. Indicates timing issues in thread binding.lane_creation_skippedβ Session lane was not created because context resolution returned null or incomplete data. Downstream ofno_active_runin the failure chain.rate_limit_exceededβ Discord API rate limiting during rapid thread creation. Can cause cascading spawn failures when multiple thread-bound subagents are requested simultaneously.- Historical Reference: Issue #892 β "Subagent spawn in DM channels fails silently" (OpenClaw v2026.1.x). Related context propagation issue resolved by ensuring run context is inherited before session creation.
- Historical Reference: Issue #1047 β "Discord thread binding delays cause message ordering issues". Documents the async Discord API latency problem that underlies the current thread-bound spawn failure.