Skip to content

Commit ed86252

Browse files
frankeknsteipete
andauthored
fix: handle CLI session expired errors gracefully instead of crashing gateway (openclaw#31090)
* fix: handle CLI session expired errors gracefully - Add session_expired to FailoverReason type - Add isCliSessionExpiredErrorMessage to detect expired CLI sessions - Modify runCliAgent to retry with new session when session expires - Update agentCommand to clear expired session IDs from session store - Add proper error handling to prevent gateway crashes on expired sessions Fixes openclaw#30986 * fix: add session_expired to AuthProfileFailureReason and missing log import * fix: type cli-runner usage field to match EmbeddedPiAgentMeta * fix: harden CLI session-expiry recovery handling * build: regenerate host env security policy swift --------- Co-authored-by: Peter Steinberger <[email protected]>
1 parent a95c807 commit ed86252

File tree

9 files changed

+460
-185
lines changed

9 files changed

+460
-185
lines changed

apps/macos/Sources/OpenClaw/HostEnvSecurityPolicy.generated.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,17 @@ enum HostEnvSecurityPolicy {
2222
"PS4",
2323
"GCONV_PATH",
2424
"IFS",
25-
"SSLKEYLOGFILE",
25+
"SSLKEYLOGFILE"
2626
]
2727

2828
static let blockedOverrideKeys: Set<String> = [
2929
"HOME",
30-
"ZDOTDIR",
30+
"ZDOTDIR"
3131
]
3232

3333
static let blockedPrefixes: [String] = [
3434
"DYLD_",
3535
"LD_",
36-
"BASH_FUNC_",
36+
"BASH_FUNC_"
3737
]
3838
}

src/agents/auth-profiles/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ export type AuthProfileFailureReason =
4343
| "billing"
4444
| "timeout"
4545
| "model_not_found"
46+
| "session_expired"
4647
| "unknown";
4748

4849
/** Per-profile usage statistics for round-robin and cooldown tracking */

src/agents/cli-runner.test.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,50 @@ describe("runCliAgent with process supervisor", () => {
153153
).rejects.toThrow("exceeded timeout");
154154
});
155155

156+
it("rethrows the retry failure when session-expired recovery retry also fails", async () => {
157+
supervisorSpawnMock.mockResolvedValueOnce(
158+
createManagedRun({
159+
reason: "exit",
160+
exitCode: 1,
161+
exitSignal: null,
162+
durationMs: 150,
163+
stdout: "",
164+
stderr: "session expired",
165+
timedOut: false,
166+
noOutputTimedOut: false,
167+
}),
168+
);
169+
supervisorSpawnMock.mockResolvedValueOnce(
170+
createManagedRun({
171+
reason: "exit",
172+
exitCode: 1,
173+
exitSignal: null,
174+
durationMs: 150,
175+
stdout: "",
176+
stderr: "rate limit exceeded",
177+
timedOut: false,
178+
noOutputTimedOut: false,
179+
}),
180+
);
181+
182+
await expect(
183+
runCliAgent({
184+
sessionId: "s1",
185+
sessionKey: "agent:main:subagent:retry",
186+
sessionFile: "/tmp/session.jsonl",
187+
workspaceDir: "/tmp",
188+
prompt: "hi",
189+
provider: "codex-cli",
190+
model: "gpt-5.2-codex",
191+
timeoutMs: 1_000,
192+
runId: "run-retry-failure",
193+
cliSessionId: "thread-123",
194+
}),
195+
).rejects.toThrow("rate limit exceeded");
196+
197+
expect(supervisorSpawnMock).toHaveBeenCalledTimes(2);
198+
});
199+
156200
it("falls back to per-agent workspace when workspaceDir is missing", async () => {
157201
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-cli-runner-"));
158202
const fallbackWorkspace = path.join(tempDir, "workspace-main");

0 commit comments

Comments
 (0)