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

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions