Skip to content

Server-execution websocket loop drops session failures with request_id:null, hanging 600s and blaming a timeout #1747

Description

@sneg55

Server-execution websocket loop drops session-level failures with request_id: null, turning a definite engine error into a 600s hang and a misleading timeout

Context: API Makeathon participant. Found while reviewing the server-execution path; independently confirmed by a second review pass.

Under server-side KCL execution, the follow-up command loop filters every response by request id before handling failures, so a session-level failure that arrives with request_id: null never matches and is silently dropped. The CLI then waits out the full response timeout and blames a timeout, hiding the real error the engine already sent.

Evidence

src/context.rs, run_server_kcl_then_modeling_cmds: the follow-up loop (around lines 545-563) does if response_request_id(&resp) != Some(cmd_id) { continue; } before it can act on a failure. FailureWebSocketResponse.request_id is Option<Uuid> and is documented as null when no request id was sent (connection-level errors, auth/entitlement failures, engine-side aborts). The response timeout is WS_RESPONSE_TIMEOUT_SECS = 600 (src/context.rs:31).

The execution loop directly above (around lines 483-530) shows the intended behavior: it bails on any WebSocketResponse::Failure regardless of request_id. The two loops are inconsistent; the second swallows exactly the class of error the first surfaces.

A related amplifier: the read helper (around src/context.rs:1554-1577) creates a fresh response cap on every call and returns after any decoded response, so heartbeat Pong frames and unrelated session-data responses reset the cap and keep the future pending rather than letting a request-level deadline fire.

Concrete failure

An account gets blocked, or the engine pool dies, between KCL execution and the follow-up Volume/Export command under server execution. The CLI sits for 10 minutes and then prints engine websocket response timed out after 600s, even though the engine already reported a definite failure. Any downstream tool that classifies CLI output sees a transport-looking timeout instead of the real engine error.

Verify

Unit-testable without the API: feed the follow-up loop a WebSocketResponse::Failure { request_id: None, errors: [sentinel] } followed by nothing. The current code discards the sentinel and hangs; the execution loop handles the same message.

Suggested fix

Handle WebSocketResponse::Failure with request_id == None || request_id == Some(cmd_id) before the id filter, mirroring the execution loop, so a session-level failure surfaces immediately.

Environment

Zoo CLI v0.2.184 (33534cd). Reviewed against the current main of KittyCAD/cli.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions