{"record":{"id":"e03aafcb6b3668c1","repo":"facebook/flow","slug":"failed-to-clear-spinner-line-e03aaf","errorCode":null,"errorMessage":"failed to clear spinner line","messagePattern":"failed to clear spinner line","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"rust_port/crates/flow_commands_connect/src/command_connect.rs","lineNumber":207,"sourceCode":"        flow_common_exit_status::exit(flow_common_exit_status::FlowExitStatus::OutOfRetries);\n    }\n\n    let has_timed_out = match env.expiry {\n        None => false,\n        Some(t) => Instant::now() >= t,\n    };\n    if has_timed_out {\n        eprintln!(\"\\nTimeout exceeded, exiting\");\n        flow_common_exit_status::exit(flow_common_exit_status::FlowExitStatus::OutOfTime);\n    }\n\n    retries.last_connect_time = Instant::now();\n\n    let conn = CCS::connect_once(env.flowconfig_name, client_handshake, env.tmp_dir, env.root);\n    if flow_utils_tty::spinner_used() {\n        let stderr = std::io::stderr();\n        let mut stderr = stderr.lock();\n        flow_utils_tty::print_clear_line(&mut stderr).expect(\"failed to clear spinner line\");\n    }\n\n    reset_retries_if_necessary(retries, &conn);\n\n    match conn {\n        Ok(conn) => conn,\n\n        Err(CCSError::ServerMissing) => handle_missing_server(env, client_handshake, retries),\n\n        Err(CCSError::ServerBusy(busy_reason)) => {\n            let busy_reason_str = match &busy_reason {\n                BusyReason::TooManyClients => \"has too many clients and rejected our connection\",\n                BusyReason::NotResponding => \"is not responding\",\n                BusyReason::FailOnInit(..) => {\n                    \"is still initializing and the client used --retry-if-init false\"\n                }\n            };\n            print_status(","sourceCodeStart":189,"sourceCodeEnd":225,"githubUrl":"https://github.com/facebook/flow/blob/5c865861998a8ccb7dbc82b0c1f511e9ef60c3d9/rust_port/crates/flow_commands_connect/src/command_connect.rs#L189-L225","documentation":"While retrying a connection to the flow server, the client clears the spinner line by writing to stderr via `print_clear_line(...).expect(\"failed to clear spinner line\")`. The panic fires when that stderr write fails — the reader of the stderr pipe has exited (EPIPE) or fd 2 is closed. Clearing the spinner is cosmetic, so the panic kills an otherwise healthy connect attempt over throwaway output.","triggerScenarios":"`flow <cmd> 2>&1 | head` where head exits during connect retries; stderr piped into a process that dies (`2> >(tee log)` with tee killed); running with fd 2 closed (`2>&-`).","commonSituations":"CLI output piped in scripts; log-shipping sidecars that close their stdin; non-interactive wrappers that close stderr descriptors.","solutions":["Keep the stderr reader alive for the whole command, or redirect stderr to a file (`2>err.log`).","If your wrapper closes fd 2, redirect it to /dev/null instead of closing it.","Code fix: ignore errors from spinner-clearing output since it is cosmetic (`let _ = print_clear_line(...)`)."],"exampleFix":"// before\nflow_utils_tty::print_clear_line(&mut stderr).expect(\"failed to clear spinner line\");\n\n// after\nlet _ = flow_utils_tty::print_clear_line(&mut stderr); // cosmetic spinner cleanup; EPIPE is fine","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Spinner output is cosmetic: never fatal\nlet _ = flow_utils_tty::print_clear_line(&mut stderr);","preventionTips":["Do not pipe stderr into readers that exit early; redirect stderr to a file or /dev/null.","Never close fd 2 outright; use 2>/dev/null instead.","Keep log-collector sidecars alive for the full command duration."],"tags":["stderr","broken-pipe","spinner","connect"],"backgroundTag":"broken-pipe","analyzedSha":"5c865861998a8ccb7dbc82b0c1f511e9ef60c3d9","analyzedAt":"2026-08-20T10:41:37.992Z","contentChangedAt":"2026-08-20T10:41:37.992Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}