{"record":{"id":"569d0656f2543234","repo":"herdrdev/herdr","slug":"editor-command-must-not-be-empty","errorCode":null,"errorMessage":"editor command must not be empty","messagePattern":"editor command must not be empty","errorType":"validation","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"src/platform/windows.rs","lineNumber":773,"sourceCode":"        });\n    scrollback_editor_argv_with_env(path, editor.as_deref())\n}\n\nfn scrollback_editor_argv_with_env(\n    path: &std::path::Path,\n    editor: Option<&str>,\n) -> std::io::Result<Vec<String>> {\n    let mut argv = match editor.filter(|value| !value.trim().is_empty()) {\n        Some(editor) => command_line_to_argv(editor).ok_or_else(|| {\n            std::io::Error::new(\n                std::io::ErrorKind::InvalidInput,\n                format!(\"failed to parse editor command {editor:?}\"),\n            )\n        })?,\n        None => vec![\"notepad.exe\".to_string()],\n    };\n    if argv.is_empty() {\n        return Err(std::io::Error::new(\n            std::io::ErrorKind::InvalidInput,\n            \"editor command must not be empty\",\n        ));\n    }\n    argv.push(path.display().to_string());\n    Ok(argv)\n}\n\npub(crate) fn configure_background_command_platform(command: &mut std::process::Command) {\n    use std::os::windows::process::CommandExt;\n\n    command.creation_flags(CREATE_NO_WINDOW);\n}\n\npub fn launch_server_daemon_command(command: &mut std::process::Command) -> std::io::Result<u32> {\n    if current_job_kills_processes_on_close()? {\n        launch_server_daemon_with_wmi(command)\n    } else {","sourceCodeStart":755,"sourceCodeEnd":791,"githubUrl":"https://github.com/herdrdev/herdr/blob/f457cff4f2648eee85d176f8a41861241d4e8428/src/platform/windows.rs#L755-L791","documentation":"After parsing the editor command on Windows, Herdr rejects an argv that tokenized to zero arguments. This happens when the editor setting is non-empty per the trim check but the parser produces no tokens (e.g. a string of only quotes or whitespace-like characters that pass trim but split to nothing).","triggerScenarios":"Calling scrollback_editor_argv_with_env with an editor value that passes the !trim().is_empty() guard yet parses to an empty argv — for example a value of just '\"\"' or characters the splitter drops entirely.","commonSituations":"EDITOR accidentally set to quote characters or invisible characters via a broken export in a shell profile; CI environments setting EDITOR='' with stray quotes; scripts writing an editor variable with formatting bugs.","solutions":["Print the editor variable to inspect it: echo \"[$EDITOR]\" | cat -A to reveal stray characters","Set EDITOR to a real command like 'code --wait' or 'notepad.exe', or unset it entirely","Re-export the variable from a clean shell profile without wrapping artifacts"],"exampleFix":"# before\nexport EDITOR='\"\"'\n# after\nexport EDITOR=\"notepad.exe\"","handlingStrategy":"validation","validationCode":"let trimmed = editor.trim();\nlet meaningful = trimmed.chars().any(|c| c != '\"' && c != '\\'');\nif trimmed.is_empty() || !meaningful {\n    // skip custom editor, use the default, before calling the API\n}","typeGuard":null,"tryCatchPattern":"Err(e) if e.kind() == std::io::ErrorKind::InvalidInput && e.to_string() == \"editor command must not be empty\" => {\n    // treat as unset: fall back to notepad.exe\n}","preventionTips":["Treat editor values composed only of quotes/whitespace as unset","Trim and inspect editor variables in setup scripts","Show the effective editor value in settings UI so misconfiguration is visible"],"tags":["windows","editor","empty-command","validation","invalid-input"],"backgroundTag":"empty-editor-command","analyzedSha":"f457cff4f2648eee85d176f8a41861241d4e8428","analyzedAt":"2026-08-28T15:41:09.197Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}