microsoft/edit · error

A language ID is required when reading from stdin

Error message

A language ID is required when reading from stdin

What it means

run_render resolves which highlighting entrypoint to use. When rendering stdin there is no file path to glob-match against entrypoint path patterns, so a language ID is mandatory; if the --language option is absent the function bails immediately.

Source

Thrown at crates/lsh-bin/src/main.rs:131

) -> anyhow::Result<()> {
    let assembly = generator.assemble()?;

    let entrypoint = if let Some(language) = language {
        assembly.entrypoints.iter().find(|ep| ep.name.replace('_', "-") == language).ok_or_else(
            || anyhow::anyhow!("No highlighting definition found for language {language:?}"),
        )?
    } else if let Some(path) = path {
        assembly
            .entrypoints
            .iter()
            .find(|ep| {
                ep.paths.iter().any(|pattern| {
                    glob_match(pattern.as_bytes(), path.as_os_str().as_encoded_bytes())
                })
            })
            .ok_or_else(|| anyhow::anyhow!("No matching highlighting definition found"))?
    } else {
        bail!("A language ID is required when reading from stdin");
    };

    let mut color_map = Vec::new();
    let mut unknown_kinds = Vec::new();
    for hk in &assembly.highlight_kinds {
        let color = match hk.identifier {
            "other" => "",

            "comment" => "\x1b[32m",  // Green
            "method" => "\x1b[93m",   // Bright Yellow
            "string" => "\x1b[91m",   // Bright Red
            "variable" => "\x1b[96m", // Bright Cyan

            "constant.language" => "\x1b[94m",    // Bright Blue
            "constant.numeric" => "\x1b[92m",     // Bright Green
            "keyword.control" => "\x1b[95m",      // Bright Magenta
            "keyword.other" => "\x1b[94m",        // Bright Blue
            "keyword.preprocessor" => "\x1b[94m", // Bright Blue

View on GitHub (pinned to 826b4c097b)

Solutions

  1. Pass the language ID when reading from stdin, e.g. `lsh --language rust` (dashes in entrypoint names map to underscores).
  2. Alternatively render an actual file path so run_render can glob-match the path against entrypoint patterns.
  3. In wrapper scripts, derive the language from the file extension before switching to stdin mode.

Example fix

// before
cat main.rs | lsh
// after
cat main.rs | lsh --language rust
Defensive patterns

Strategy: validation

Validate before calling

let lang = language_arg.ok_or("--language is required when piping to stdin")?;
if input_is_stdin && lang.is_none() {
    eprintln!("usage: cat file | lsh --language rust");
    std::process::exit(2);
}

Prevention

When it happens

Trigger: Piping content to lsh via stdin without specifying a language ID, i.e. language is None and path is also None when run_render is called from run.

Common situations: Running `cat file.rs | lsh` instead of `cat file.rs | lsh --language rust`; editors/CI integrations invoking lsh on stdin without wiring through the language flag from their config.

Understand the failure class

Background: "--flag is required" and "must specify" CLI errors: how missing-required-flag validation works and how to fix it — this error's family across 20 libraries.

Related errors


AI-assisted analysis of microsoft/edit@826b4c097b (2026-09-06). Data as JSON: /api/errors/46554774524ba2dc. Report an issue: GitHub.