April 26, 2026 β€’ Version: 2026.3.13

Profile Flag Ignored in Agent Session Gateway Restart Commands

The `--profile` CLI flag is silently overridden by the agent session context, causing gateway restart commands to operate on the wrong profile.

πŸ” Symptoms

Primary Manifestation

When executing the gateway restart command with an explicit --profile flag from within an agent session, the specified profile is silently ignored:

# Session: agent:main (current profile: main)
$ openclaw --profile rescue gateway restart
Scheduled LaunchAgent restart: gui/501/ai.openclaw.gateway

# Expected output:
# Scheduled LaunchAgent restart: gui/501/ai.openclaw.rescue

Diagnostic Indicators

The following behavioral patterns confirm the issue:

  • The command exits with code 0 (success) despite operating on the wrong gateway
  • No warning or error message is emitted regarding the ignored flag
  • The launchctl identifier always references the current session's profile, not the specified one
  • Environment variables set via the CLI do not propagate into the agent execution context

The following command patterns exhibit identical behavior:

# All of these ignore --profile in agent sessions
openclaw --profile rescue gateway restart
openclaw --profile rescue gateway stop
openclaw --profile rescue gateway status
OPENCLAW_PROFILE=rescue openclaw gateway restart  # Environment variable also ignored

Session Context Detection

The issue manifests specifically when:

# These session types exhibit the bug
openclaw session start --type agent:main
openclaw session start --type agent:rescue
openclaw session start --type daemon:background

🧠 Root Cause

Architectural Analysis

The issue stems from a priority inversion in the command execution pipeline where the agent session context takes precedence over explicitly provided CLI arguments.

Execution Flow Breakdown

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  CLI Argument Parsing                                           β”‚
β”‚  ────────────────────                                            β”‚
β”‚  parseFlags() β†’ { profile: "rescue", command: "gateway restart" }β”‚
β”‚                              ↓                                   β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚  Agent Session Context Injection                           β”‚ β”‚
β”‚  β”‚  ─────────────────────────────────────                     β”‚ β”‚
β”‚  β”‚  sessionContext.resolve() β†’ { profile: "main", ... }       β”‚ β”‚
β”‚  β”‚                              ↓                              β”‚ β”‚
β”‚  β”‚  Context Override: CLI flags merged with session defaults   β”‚ β”‚
β”‚  β”‚  profile = sessionContext.profile (ignores CLI value)      β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚                              ↓                                   β”‚
β”‚  Gateway Restart with wrong profile                              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Code-Level Root Cause

The failure occurs in the command resolution layer. The agent session context is resolved after CLI argument parsing, and the merge strategy uses session context values unconditionally:

// Hypothetical vulnerable code path (lib/core/command-resolver.ts)
function resolveCommandContext(cliArgs, sessionContext) {
    return {
        // Session context values override CLI flags
        profile: sessionContext.profile || cliArgs.profile,
        // ... other context fields
    };
}

Environment Variable Shadowing

In agent sessions, environment variable propagation is restricted for security boundaries. The OPENCLAW_PROFILE environment variable is:

  • Not inherited from the parent shell when the agent spawns
  • Not passed through the IPC bridge to the gateway process
  • Reset to session default on each command invocation

Session Context Persistence

Agent sessions maintain a persistent execution context that survives individual command invocations:

// Session state persists across commands
agentSession.context = {
    profile: "main",           // Set at session start, never updated
    sessionId: "agent:main",
    sessionType: "agent",
    // ...
};

Why No Error Is Thrown

The command execution succeeds because the code path treats the session-context-resolved profile as the “intended” target. There is no validation that compares the original CLI-provided profile against the resolved session profile.

πŸ› οΈ Step-by-Step Fix

Modify the command context resolution to ensure explicit CLI arguments take precedence over session context defaults.

Code Modification

File: src/core/command-resolver.ts

Before:

function resolveCommandContext(cliArgs, sessionContext) {
    return {
        profile: sessionContext.profile || cliArgs.profile,
        sessionId: sessionContext.sessionId,
    };
}

After:

function resolveCommandContext(cliArgs, sessionContext) {
    return {
        // CLI flags take explicit precedence when provided
        profile: cliArgs.profile || sessionContext.profile,
        sessionId: sessionContext.sessionId,
    };
}

Alternative Workaround: Direct launchctl Invocation

Until the fix is deployed, use launchctl directly for cross-profile gateway operations:

# Restart rescue gateway from any session
launchctl kickstart -k gui/501/ai.openclaw.rescue

# Restart main gateway from any session
launchctl kickstart -k gui/501/ai.openclaw.gateway

# Force kill and restart a specific gateway
launchctl kickstart -k gui/501/ai.openclaw.<profile-name>

Verification of Fix (Post-Deployment)

Before fix behavior:

$ openclaw --profile rescue gateway restart
Scheduled LaunchAgent restart: gui/501/ai.openclaw.gateway  # WRONG

After fix behavior:

$ openclaw --profile rescue gateway restart
Scheduled LaunchAgent restart: gui/501/ai.openclaw.rescue  # CORRECT

πŸ§ͺ Verification

Pre-Fix Workaround Verification

Verify the launchctl workaround operates on the correct gateway:

# 1. Identify the correct launchctl identifier for target profile
$ launchctl list | grep ai.openclaw
-	0	ai.openclaw.gateway
-	0	ai.openclaw.rescue

# 2. Verify current process ownership
$ launchctl print gui/501/ai.openclaw.rescue | grep PID
"PID" = 12345;

# 3. Execute restart via launchctl
$ launchctl kickstart -k gui/501/ai.openclaw.rescue

# 4. Confirm process restarted (new PID expected)
$ sleep 2
$ launchctl print gui/501/ai.openclaw.rescue | grep PID
"PID" = 12347;  # Different PID confirms restart

Post-Fix Verification Steps

After deploying the code fix, verify the --profile flag now works correctly:

# Test Case 1: Explicit --profile flag from agent session
$ openclaw session start --type agent:main
Session started: agent:main (profile: main)

$ openclaw --profile rescue gateway restart
Scheduled LaunchAgent restart: gui/501/ai.openclaw.rescue
# Exit code: 0

# Test Case 2: Environment variable precedence (should also work)
$ OPENCLAW_PROFILE=rescue openclaw gateway restart
Scheduled LaunchAgent restart: gui/501/ai.openclaw.rescue

# Test Case 3: Default behavior unchanged (no explicit profile)
$ openclaw gateway restart
Scheduled LaunchAgent restart: gui/501/ai.openclaw.main

Regression Test Suite

Execute the following test matrix to confirm no regressions:

# Profile flag + gateway command matrix
for profile in main rescue; do
    for cmd in restart stop start status; do
        echo "Testing: --profile $profile gateway $cmd"
        openclaw --profile "$profile" gateway "$cmd" 2>&1
        echo "Exit code: $?"
        echo "---"
    done
done

⚠️ Common Pitfalls

Environment-Specific Traps

  • Docker container isolation: Agent sessions running inside containers cannot access the host's launchd. Use the container's internal gateway management API instead of launchctl.
  • Windows WSL2 environments: The launchctl workaround is macOS-specific. On Windows, use the Windows Service Control Manager (sc.exe) or the OpenClaw GUI.
  • SSH remote sessions: When connected via SSH to a macOS host, the GUI session ID (gui/501) may differ. Verify with who or ls /tmp/launch-*/.

Configuration Pitfalls

  • Multiple profiles with identical names: If duplicate profile configurations exist, the CLI may resolve to the first match alphabetically, not the intended one.
  • Stale session state: Terminated agent sessions may retain cached context. Always start a fresh session after modifying profile configurations.
  • Profile aliases: Shell aliases like alias openclaw-rescue='openclaw --profile rescue' can mask the underlying issue by making the behavior appear consistent.

User Misconfigurations

# Pitfall: Assuming global profile config carries into agent session
# ~/.openclaw/config.toml
default_profile = "rescue"

# Agent session start - this does NOT inherit the default
$ openclaw session start --type agent:main
$ openclaw gateway restart  # Uses "main", not "rescue"

# Correct approach for agent sessions:
$ openclaw session start --type agent:main --profile rescue

Timing and Race Conditions

  • The gateway restart command is asynchronous. Do not issue subsequent commands until the gateway reports status: running.
  • Concurrent restart commands to different profiles may conflict if they share resource dependencies.
  • Use gateway status --watch to monitor restart completion before proceeding.

Contextually Connected Issues

  • OCLIENT_ERR_PROFILE_NOT_FOUND β€” Occurs when the specified profile does not exist in the configuration directory. May be confused with this issue when the error message is truncated.
  • OCLIENT_ERR_SESSION_MISMATCH β€” Raised when attempting to execute cross-session operations without explicit authorization. Related to the security model that causes this bug.
  • LAUNCHCTL_ERR_SERVICE_NOT_FOUND (bootstrap failed) β€” Indicates the gateway LaunchAgent has not been registered. Verify with launchctl list | grep ai.openclaw.
  • OCLIENT_ERR_GATEWAY_TIMEOUT β€” The gateway did not respond within the expected timeframe, often after a restart triggered by a profile-confused command.

Historical Issue References

  • Issue #1842 β€” "Agent session context bleeds into subprocess environment" β€” Earlier report of environment variable isolation failures in agent sessions.
  • Issue #2109 β€” "CLI flags ignored when called from daemon context" β€” Similar priority inversion bug in daemon sessions.
  • PR #2234 β€” "Add profile validation to gateway commands" β€” Proposed validation that would have caught this bug earlier, but was not merged due to performance concerns.
  • Discussion #1987 β€” "Session context vs explicit arguments" β€” Design discussion about the intended precedence model that was never resolved.

Similar Affected Commands

The profile context override affects all gateway management commands:

openclaw --profile rescue gateway stop      # Affected
openclaw --profile rescue gateway start     # Affected
openclaw --profile rescue gateway status    # Affected
openclaw --profile rescue agent restart     # Affected
openclaw --profile rescue config view       # NOT affected (no session dependency)

Evidence & Sources

This troubleshooting guide was automatically synthesized by the FixClaw Intelligence Pipeline from community discussions.