{"record":{"id":"fb1316f17e07f08b","repo":"facebook/flow","slug":"failed-to-write-vim-emacs-errors","errorCode":null,"errorMessage":"failed to write vim/emacs errors","messagePattern":"failed to write vim/emacs errors","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"rust_port/crates/flow_cli/src/status_command.rs","lineNumber":193,"sourceCode":"            suppressed_errors,\n        } => {\n            let error_flags = &args.error_flags;\n            let from = flow_event_logger::get_from_i_am_a_clown();\n            if args.output_json {\n                print_json(&errors, &warnings, &suppressed_errors)\n            } else if matches!(from.as_deref(), Some(\"vim\") | Some(\"emacs\")) {\n                let strip_root = strip_root\n                    .as_deref()\n                    .map(|root| root.to_string_lossy().into_owned());\n                let stdout = std::io::stdout();\n                let mut out = stdout.lock();\n                flow_common_errors::error_utils::vim_emacs_output::print_errors(\n                    strip_root.as_deref(),\n                    &mut out,\n                    &errors,\n                    &warnings,\n                )\n                .expect(\"failed to write vim/emacs errors\");\n                out.flush().expect(\"failed to flush vim/emacs errors\");\n            } else {\n                let mut cli_errors = errors.clone();\n                for (error, _) in &suppressed_errors {\n                    cli_errors.add(error.clone());\n                }\n                let stdout = std::io::stdout();\n                let mut out = stdout.lock();\n                flow_common_errors::error_utils::cli_output::print_errors(\n                    &mut out,\n                    error_flags,\n                    &None,\n                    strip_root.as_deref(),\n                    &cli_errors,\n                    &warnings,\n                    lazy_msg.as_deref(),\n                )\n                .expect(\"failed to write cli errors\");","sourceCodeStart":175,"sourceCodeEnd":211,"githubUrl":"https://github.com/facebook/flow/blob/5c865861998a8ccb7dbc82b0c1f511e9ef60c3d9/rust_port/crates/flow_cli/src/status_command.rs#L175-L211","documentation":"With `flow status --from vim` (or emacs), the CLI writes errors in the vim/emacs quickfix format directly to a locked stdout for editor integrations; this expect panics on the first write error. The classic cause is the editor-side pipe disappearing — the user quits the editor, the plugin's job is cancelled, or the process group is killed — while flow is still writing error lines.","triggerScenarios":"A vim/emacs flow plugin spawns `flow status --from vim`, the user closes the buffer/editor or a new keystroke cancels the job, and the pipe reader exits before flow finishes writing the quickfix list.","commonSituations":"Editor integrations (ALE-style, flow-language-plugin) that spawn status requests and cancel them on new input; users quitting vim mid-check; flaky EPIPE panics littering editor plugin logs.","solutions":["In the editor plugin, keep the job's pipe open until the flow process exits (await process completion, e.g. Neovim jobwait / job_close after exit).","Debounce/cancel cleanly: kill the flow process instead of just closing its stdout pipe.","For manual debugging, redirect to a file: `flow status --from vim > /tmp/errors`.","Maintainer fix: treat BrokenPipe as a normal cancellation and exit 0 silently."],"exampleFix":"# before (editor plugin shell)\nflow status --from vim | head -100   # head exits, flow panics on EPIPE\n\n# after (editor plugin shell)\nflow status --from vim > /tmp/flow-errors.$$\n# then read the full file","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if let Err(e) = flow_common_errors::error_utils::vim_emacs_output::print_errors(strip_root.as_deref(), &mut out, &errors, &warnings) {\n    if e.kind() == std::io::ErrorKind::BrokenPipe {\n        std::process::exit(0); // editor went away; treat as cancelled\n    }\n    panic!(\"failed to write vim/emacs errors: {}\", e);\n}","preventionTips":["Editor plugins must keep the spawned flow process's stdout open until the process exits (await exit, then close).","Cancel in-flight requests by terminating the process, not by closing the pipe.","Redirect to a temp file when debugging editor integrations."],"tags":["stdout","broken-pipe","vim","emacs","editor-integration","panic"],"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"}