{"record":{"id":"448b2b57c81545d9","repo":"sigoden/aichat","slug":"invalid-document-loader-extension-loader-co","errorCode":null,"errorMessage":"Invalid document loader '{extension}': `{loader_command}`","messagePattern":"Invalid document loader '(.+?)': `(.+?)`","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/utils/command.rs","lineNumber":110,"sourceCode":"\npub fn run_command_with_output<T: AsRef<OsStr>>(\n    cmd: &str,\n    args: &[T],\n    envs: Option<HashMap<String, String>>,\n) -> Result<(bool, String, String)> {\n    let output = Command::new(cmd)\n        .args(args.iter())\n        .envs(envs.unwrap_or_default())\n        .output()?;\n    let status = output.status;\n    let stdout = std::str::from_utf8(&output.stdout).context(\"Invalid UTF-8 in stdout\")?;\n    let stderr = std::str::from_utf8(&output.stderr).context(\"Invalid UTF-8 in stderr\")?;\n    Ok((status.success(), stdout.to_string(), stderr.to_string()))\n}\n\npub fn run_loader_command(path: &str, extension: &str, loader_command: &str) -> Result<String> {\n    let cmd_args = shell_words::split(loader_command)\n        .with_context(|| anyhow!(\"Invalid document loader '{extension}': `{loader_command}`\"))?;\n    let mut use_stdout = true;\n    let outpath = temp_file(\"-output-\", \"\").display().to_string();\n    let cmd_args: Vec<_> = cmd_args\n        .into_iter()\n        .map(|mut v| {\n            if v.contains(\"$1\") {\n                v = v.replace(\"$1\", path);\n            }\n            if v.contains(\"$2\") {\n                use_stdout = false;\n                v = v.replace(\"$2\", &outpath);\n            }\n            v\n        })\n        .collect();\n    let cmd_eval = shell_words::join(&cmd_args);\n    debug!(\"run `{cmd_eval}`\");\n    let (cmd, args) = cmd_args.split_at(1);","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/sigoden/aichat/blob/82976d349ad97ac9aae0655ad631dace5e2a6385/src/utils/command.rs#L92-L128","documentation":"`run_loader_command` builds the loader command line with `shell_words::split(loader_command)`; when that parser rejects the string (unbalanced quotes, trailing backslash, unterminated escape), it wraps the parse error as \"Invalid document loader '{extension}': `{loader_command}`\". The extension identifies which configured loader was at fault, and the loader_command is echoed so the misconfiguration is visible.","triggerScenarios":"Calling `load_with_command`/`load_recursive_url`/`load_protocol_path`/`fetch_with_loaders` with a loader command string that `shell_words::split` cannot tokenize, e.g. `pandoc -f \"markdown` (unterminated quote) or a dangling `\\`.","commonSituations":"Typo in a loader definition in config (unbalanced quotes, stray backslash); copy-pasting commands with smart quotes or Windows-style quoting; environment-specific quoting that shell_words cannot parse.","solutions":["Inspect the loader command for the given extension and fix unbalanced quotes, smart quotes, or dangling backslashes.","Test the command string with `shell_words::split` semantics: plain space-separated tokens with single/double quoting.","Validate loader commands at config-load time instead of at fetch time.","Replace problematic quoting with simpler argument lists (no embedded quotes) if possible."],"exampleFix":"// before\nloaders.insert(\"pdf\", \"pdftotext - \\\"$1\\\"\"); // unbalanced quote -> Invalid document loader 'pdf'\n// after\nloaders.insert(\"pdf\", \"pdftotext - $1\");","handlingStrategy":"validation","validationCode":"fn validate_loader_command(cmd: &str) -> Result<(), String> {\n    match shell_words::split(cmd) {\n        Ok(args) if !args.is_empty() => Ok(()),\n        Ok(_) => Err(\"loader command is empty\".into()),\n        Err(e) => Err(format!(\"cannot tokenize loader command {cmd:?}: {e}\")),\n    }\n}","typeGuard":null,"tryCatchPattern":"match run_loader_command(path, ext, &cmd) {\n    Err(e) if e.to_string().starts_with(\"Invalid document loader\") => {\n        eprintln!(\"Check the loader definition for '{ext}': {e}\");\n    }\n    other => other?,\n}","preventionTips":["Validate all loader commands with shell_words::split at config load time.","Avoid smart quotes and unbalanced quoting in loader definitions.","Keep loader commands as simple space-separated token lists.","Echo the failing extension/command in config-parse errors so typos are obvious."],"tags":["shell","parsing","configuration","loader"],"backgroundTag":"invalid-argument-format","analyzedSha":"82976d349ad97ac9aae0655ad631dace5e2a6385","analyzedAt":"2026-09-09T18:33:06.139Z","contentChangedAt":"2026-09-09T18:33:06.139Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}