{"record":{"id":"3a125f4bcb57625c","repo":"rust-lang/mdBook","slug":"command-string-was-empty","errorCode":null,"errorMessage":"Command string was empty","messagePattern":"Command string was empty","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/mdbook-driver/src/lib.rs","lineNumber":86,"sourceCode":"pub mod builtin_renderers;\npub mod init;\nmod load;\nmod mdbook;\n\nuse anyhow::{Context, Result, bail};\npub use mdbook::MDBook;\npub use mdbook_core::{book, config, errors};\nuse shlex::Shlex;\nuse std::path::{Path, PathBuf};\nuse std::process::Command;\nuse tracing::{error, warn};\n\n/// Creates a [`Command`] for command renderers and preprocessors.\nfn compose_command(cmd: &str, root: &Path) -> Result<Command> {\n    let mut words = Shlex::new(cmd);\n    let exe = match words.next() {\n        Some(e) => PathBuf::from(e),\n        None => bail!(\"Command string was empty\"),\n    };\n\n    let exe = if exe.components().count() == 1 {\n        // Search PATH for the executable.\n        exe\n    } else {\n        // Relative path is relative to book root.\n        root.join(&exe)\n    };\n\n    let mut cmd = Command::new(exe);\n\n    for arg in words {\n        cmd.arg(arg);\n    }\n\n    Ok(cmd)\n}","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/rust-lang/mdBook/blob/dc21064fc21d955a0e1f67e65e336883c3e5260b/crates/mdbook-driver/src/lib.rs#L68-L104","documentation":"mdbook's compose_command builds a std::process::Command for an external renderer or preprocessor by shell-splitting the command string with Shlex. If the configured command string is empty (or contains only whitespace), there is no executable to run, so the library bails with this error instead of spawning an invalid process. It is a configuration validation error surfaced as a Result::Err.","triggerScenarios":"Setting a renderer or preprocessor command in book.toml to an empty string (e.g. `output.xyz.command = \"\"` or `[preprocessor.foo]\\ncommand = \"\"`), or passing an empty/whitespace-only cmd to any code path that calls compose_command.","commonSituations":"Empty command inherited from an environment variable interpolation (e.g. MY_CMD=\"\" mdbook build), a config templating step that dropped the value, or hand-edited book.toml where the command value was accidentally deleted but the key kept.","solutions":["Set a non-empty command for the renderer/preprocessor in book.toml, e.g. command = \"mdbook-foo\".","If the command comes from an environment variable, ensure the variable is exported with the actual executable path before running mdbook.","Remove the empty command key entirely so mdbook uses its default lookup for the preprocessor/renderer.","If writing a plugin, validate the command string is non-empty (Shlex-parses to at least one token) before registering."],"exampleFix":"// before (book.toml)\n[preprocessor.links]\ncommand = \"\"\n\n// after (book.toml)\n[preprocessor.links]\ncommand = \"mdbook-links\"","handlingStrategy":"validation","validationCode":"let cmd = config.get(\"output.my-renderer.command\").unwrap_or(\"\");\nif cmd.trim().is_empty() {\n    return Err(anyhow!(\"renderer command must be a non-empty string\"));\n}","typeGuard":"fn has_command(cmd: &Option<String>) -> bool {\n    cmd.as_deref().map(|c| !c.trim().is_empty()).unwrap_or(false)\n}","tryCatchPattern":null,"preventionTips":["Always set an explicit non-empty command for custom renderers/preprocessors.","Check environment-variable interpolation in book.toml resolves to a non-empty value.","Run `mdbook build` in CI to catch config regressions early."],"tags":["configuration","cli","shell-parsing"],"backgroundTag":"empty-command-config-value","analyzedSha":"dc21064fc21d955a0e1f67e65e336883c3e5260b","analyzedAt":"2026-09-01T10:15:12.134Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}