fix(nodes): raise transport timeout for exec.approval.request (#12098) (#12188)

`openclaw nodes run` always timed out after 35s with "gateway timeout
after 35000ms" even though `openclaw nodes invoke system.run` worked
instantly on the same node.

Root cause: the CLI's default --timeout of 35s was used as the WebSocket
transport timeout for exec.approval.request, but the gateway-side
handler waits up to 120s for user approval — so the transport was always
killed 85s too early.

Fix: override opts.timeout for the approval call to
Math.max(parseTimeoutMs(opts.timeout) ?? 0, approvalTimeoutMs + 10_000)
(130s by default), ensuring the transport outlasts the approval wait
while still honoring any larger user-supplied --timeout.
This commit is contained in:
Marcus Castro
2026-02-14 21:00:01 -03:00
committed by GitHub
parent c8c8fc4530
commit 82c1d9d3ef
2 changed files with 118 additions and 2 deletions

View File

@@ -272,7 +272,19 @@ export function registerNodesInvokeCommands(nodes: Command) {
let approvalId: string | null = null;
if (requiresAsk) {
approvalId = crypto.randomUUID();
const decisionResult = (await callGatewayCli("exec.approval.request", opts, {
const approvalTimeoutMs = 120_000;
// The CLI transport timeout (opts.timeout) must be longer than the
// gateway-side approval wait so the connection stays alive while the
// user decides. Without this override the default 35 s transport
// timeout races — and always loses — against the 120 s approval
// timeout, causing "gateway timeout after 35000ms" (#12098).
const approvalOpts = {
...opts,
timeout: String(
Math.max(parseTimeoutMs(opts.timeout) ?? 0, approvalTimeoutMs + 10_000),
),
};
const decisionResult = (await callGatewayCli("exec.approval.request", approvalOpts, {
id: approvalId,
command: rawCommand ?? argv.join(" "),
cwd: opts.cwd,
@@ -282,7 +294,7 @@ export function registerNodesInvokeCommands(nodes: Command) {
agentId,
resolvedPath: undefined,
sessionKey: undefined,
timeoutMs: 120_000,
timeoutMs: approvalTimeoutMs,
})) as { decision?: string } | null;
const decision =
decisionResult && typeof decisionResult === "object"