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
launchctlidentifier 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
Related Command Variations Affected
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
Recommended Solution: Explicit CLI Flag Precedence
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 oflaunchctl. - Windows WSL2 environments: The
launchctlworkaround 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 withwhoorls /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 restartcommand is asynchronous. Do not issue subsequent commands until the gateway reportsstatus: running. - Concurrent restart commands to different profiles may conflict if they share resource dependencies.
- Use
gateway status --watchto monitor restart completion before proceeding.
π Related Errors
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(bootstrapfailed) β Indicates the gateway LaunchAgent has not been registered. Verify withlaunchctl 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)