{"record":{"id":"3bdfea774c244018","repo":"microsoft/edit","slug":"at-least-one-lsh-file-or-directory-is-required","errorCode":null,"errorMessage":"At least one .lsh file or directory is required","messagePattern":"At least one \\.lsh file or directory is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/lsh-bin/src/main.rs","lineNumber":78,"sourceCode":"pub fn main() {\n    if let Err(e) = run() {\n        eprintln!(\"{e}\");\n        exit(1);\n    }\n}\n\nfn run() -> anyhow::Result<()> {\n    stdext::arena::init(128 * 1024 * 1024).unwrap();\n\n    let command: Command = argh::from_env();\n    let scratch = scratch_arena(None);\n    let mut generator = lsh::compiler::Generator::new(&scratch);\n    let mut read_lsh = |path: &Path| {\n        if path.is_dir() { generator.read_directory(path) } else { generator.read_file(path) }\n    };\n    let mut read_lsh_inputs = |paths: &[PathBuf]| -> anyhow::Result<()> {\n        if paths.is_empty() {\n            bail!(\"At least one .lsh file or directory is required\");\n        }\n\n        for path in paths {\n            read_lsh(path)?;\n        }\n\n        Ok(())\n    };\n\n    match &command.sub {\n        SubCommands::Compile(cmd) => {\n            read_lsh_inputs(&cmd.lsh)?;\n            let output = generator.generate_rust()?;\n            _ = stdout().write_all(output.as_bytes());\n        }\n        SubCommands::Assembly(cmd) => {\n            read_lsh_inputs(&cmd.lsh)?;\n            let vt = stdout().is_terminal();","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/microsoft/edit/blob/826b4c097b6f14ba0a846dc56f2f0223a3aaf73a/crates/lsh-bin/src/main.rs#L60-L96","documentation":"The lsh binary's run function validates its positional input paths before compiling. If no .lsh files or directories were supplied on the command line, there is nothing for the Generator to read, so it aborts with bail!(). It is a hard CLI usage error, not a runtime failure.","triggerScenarios":"Invoking the lsh binary without any positional path arguments (the paths slice passed to read_lsh_inputs is empty), e.g. running `lsh` with no file or directory operands.","commonSituations":"Forgetting the input path when scripting lsh; a wrapper script that expands a glob to nothing; CI jobs where the .lsh source directory was not checked out or is empty so shell globs expand to zero arguments.","solutions":["Pass at least one .lsh file or directory containing highlighting definitions as a positional argument.","Verify the glob/path in your wrapper script actually matches existing files (use `ls` on the pattern) before invoking lsh.","Check CI checkout steps ensure the .lsh sources exist in the working directory."],"exampleFix":"// before\nlsh\n// after\nlsh syntax/ definitions/ || lsh ./syntax.lsh","handlingStrategy":"validation","validationCode":"const PATHS: &[&str] = &[\"syntax/\"]; // resolve globs eagerly\nlet resolved: Vec<PathBuf> = PATHS.iter().flat_map(|p| glob(p).expect(\"glob\")).collect();\nif resolved.is_empty() { eprintln!(\"no .lsh inputs found\"); std::process::exit(2); }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pass an explicit .lsh file or directory when scripting lsh.","In shell scripts, fail fast if a glob expands to nothing (set -euo pipefail + nullglob checks).","Assert in CI that the definitions directory is non-empty before running lsh."],"tags":["cli","missing-input","usage-error"],"backgroundTag":"missing-required-argument","analyzedSha":"826b4c097b6f14ba0a846dc56f2f0223a3aaf73a","analyzedAt":"2026-09-06T13:30:05.543Z","contentChangedAt":"2026-09-06T13:30:05.543Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}