warpdotdev/warp · error

Failed to parse Grep output, unexpected format

Error message

Failed to parse Grep output, unexpected format

What it means

The grep output parser expects every line to contain at least 'file:line-number' as the first two colon-separated fields. A line where either the file or line-number slot is missing - blank lines, 'Binary file x matches', banners, or grep diagnostics without that shape - fails the whole parse with this error.

Source

Thrown at app/src/ai/blocklist/action_model/execute/grep.rs:656

/// Parses the output of grep or a grep-like command into the format that we pass
/// back to the agent.
///
/// Assumes the output is in the format:
/// `{relative_file_path}:{line_number}:{line_contents}`.
fn parse_grep_output(
    output: &str,
    shell_launch_data: Option<ShellLaunchData>,
    current_working_directory: Option<String>,
) -> anyhow::Result<Vec<GrepFileMatch>> {
    let mut matched_files = HashMap::new();

    for line in output.trim().split("\n") {
        let mut parts = line.split(":");
        let file = parts.next();
        let line_number = parts.next();

        let (Some(file), Some(line_number)) = (file, line_number) else {
            return Err(anyhow::anyhow!(
                "Failed to parse Grep output, unexpected format"
            ));
        };
        let line_number = match line_number.parse::<usize>() {
            Ok(line_number) => line_number,
            Err(e) => {
                return Err(anyhow::anyhow!(
                    "Failed to parse line number in Grep output: {:?}",
                    e
                ));
            }
        };

        matched_files
            .entry(file)
            .or_insert_with(Vec::new)
            .push(GrepLineMatch { line_number });
    }

View on GitHub (pinned to e72fd7aacb)

Solutions

  1. Invoke grep with flags that pin the format: -n, --no-messages (-s), and -I to skip binaries
  2. Strip blank lines and known banner lines before parsing
  3. Make the parser skip-and-warn on malformed lines instead of failing the entire result
  4. Pin the grep implementation used across platforms

Example fix

// before
for line in output.trim().split("\n") {
    let mut parts = line.split(":");
    let (Some(file), Some(line_number)) = (parts.next(), parts.next()) else {
        return Err(anyhow::anyhow!("Failed to parse Grep output, unexpected format"));
    };
}

// after
for line in output.trim().split("\n") {
    let mut parts = line.split(":");
    let (Some(file), Some(line_number)) = (parts.next(), parts.next()) else {
        log::warn!("Skipping malformed grep line: {line:?}");
        continue;
    };
}
Defensive patterns

Strategy: fallback

Validate before calling

let parseable = output.lines().all(|l| {
    let mut p = l.split(':');
    matches!((p.next(), p.next()), (Some(f), Some(n)) if !f.is_empty() && n.parse::<usize>().is_ok())
});
if !parseable { sanitize_output_before_parsing(output); }

Type guard

fn is_grep_match_line(line: &str) -> bool {
    let mut p = line.split(':');
    matches!((p.next(), p.next()), (Some(f), Some(n))
        if !f.is_empty() && !f.starts_with("grep") && n.parse::<usize>().is_ok())
}

Try / catch

match parse_grep_output(&output, shell, cwd).await {
    Err(e) if e.to_string().contains("unexpected format") => {
        let clean: String = output.lines().filter(|l| is_grep_match_line(l)).collect::<Vec<_>>().join("\n");
        parse_grep_output(&clean, shell, cwd).await // retry on filtered output
    }
    r => r,
}

Prevention

When it happens

Trigger: Output passed to the parser contains a line whose split(':') yields fewer than two parts: blank trailing lines, 'Binary file ... matches' entries, command banners, or truncated output (grep.rs:649-658).

Common situations: Grep invoked without flags that guarantee the file:line format (missing -n, no --no-messages); binary files matched; stderr or headers mixed into stdout; output from a different grep implementation (BSD/GNU/BusyBox) with different formatting.

Understand the failure class

Related errors


AI-assisted analysis of warpdotdev/warp@e72fd7aacb (2026-08-16). Data as JSON: /api/errors/6eb0a846819ae981. Report an issue: GitHub.