aaif-goose/goose · error
Invalid editor command: unmatched quotes in '{editor_cmd}'
Error message
Invalid editor command: unmatched quotes in '{editor_cmd}' What it means
split_editor_command switches to shlex splitting when the configured editor command contains quote characters, and shlex::split returns None for unbalanced or mismatched quotes — goose surfaces that as this error. Any stray '"' or "'" in the editor string (an opening quote never closed, or a wrapped value pasted with its quotes into the config) triggers it.
Source
Thrown at crates/goose-cli/src/session/editor.rs:151
}
}
impl Drop for SymlinkCleanup {
fn drop(&mut self) {
let _ = std::fs::remove_file(&self.symlink_path);
}
}
/// Split an editor command into program and arguments.
///
/// Uses shell-word splitting only when the command contains quotes, so values like
/// `"/Applications/Sublime Text.app/.../subl" -w` work. Unquoted commands are split on
/// whitespace to avoid shlex stripping backslashes from Windows paths like
/// `C:\Windows\System32\notepad.exe`.
fn split_editor_command(editor_cmd: &str) -> Result<Vec<String>> {
if editor_cmd.contains(['"', '\'']) {
shlex::split(editor_cmd).ok_or_else(|| {
anyhow::anyhow!("Invalid editor command: unmatched quotes in '{editor_cmd}'")
})
} else {
Ok(editor_cmd.split_whitespace().map(String::from).collect())
}
}
/// Launch editor and wait for completion
fn launch_editor(editor_cmd: &str, file_path: &PathBuf) -> Result<()> {
use std::process::Stdio;
let parts = split_editor_command(editor_cmd)?;
if parts.is_empty() {
return Err(anyhow::anyhow!("Empty editor command"));
}
let mut cmd = Command::new(&parts[0]);
if let Ok(cwd) = std::env::current_dir() {
cmd.current_dir(cwd);View on GitHub (pinned to 3810898a74)
Solutions
- Inspect the configured editor value (`goose config get editor` or the config file) and fix the quoting: every opening quote must have a matching closing quote.
- Store the value without the shell-style wrapper quotes — config files don't need them: `editor = 'subl -w'` in TOML means the value is subl -w.
- Quote only the path with spaces: `"/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl" -w`.
- After fixing, re-run the command that opens the editor.
Example fix
# before (config value literally contains unmatched quotes) editor = "/opt/Sublime Text.app/subl -w # closing quote lost # after editor = '"/opt/Sublime Text.app/subl" -w'
Defensive patterns
Strategy: validation
Validate before calling
fn editor_command_is_balanced(cmd: &str) -> bool {
let mut double = 0i32;
let mut single = 0i32;
for ch in cmd.chars() {
if ch == '"' { double += 1; }
if ch == '\'' { single += 1; }
}
double % 2 == 0 && single % 2 == 0
}
// run before storing/using the editor config; better: shlex::split(cmd).is_some() Type guard
fn is_valid_editor_command(cmd: &str) -> bool {
if cmd.contains(['"', '\'']) {
shlex::split(cmd).is_some()
} else {
!cmd.split_whitespace().next().is_none()
}
} Try / catch
match launch_editor(&editor_cmd, &path) {
Err(e) if e.to_string().contains("unmatched quotes") => {
eprintln!("fix editor config: quote the program path properly, no stray quotes");
}
r => r,
} Prevention
- In config files, store the editor value without shell wrapper quotes.
- Quote only path segments containing spaces, and always close what you open.
- Validate the editor string with shlex::split when saving the config.
When it happens
Trigger: Editor config like `"/Applications/Sublime Text.app/.../subl -w` (closing quote missing), `vim -c 'set ft=markdown` (unclosed single quote), or a value stored WITH surrounding quotes that were part of a shell example rather than the value.
Common situations: Copy-pasting `EDITOR='subl -w'` including the outer quotes into a TOML/JSON config so the stored value becomes `'subl -w'` with literal quotes; hand-editing config files and leaving a dangling quote; passwords/spaces arguments with asymmetric quoting.
Related errors
- Empty editor command
- TLS was requested but no TLS backend is enabled. Enable the
- goose configure requires an interactive terminal. If you ins
- Failed to create provider for OAuth: {}
- invalid thinking effort
AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16).
Data as JSON: /api/errors/fe913dcbefd78c54.
Report an issue: GitHub.