rtk-ai/rtk · error · anyhow::Error

Failed to parse binlog at {}: empty file

Error message

Failed to parse binlog at {}: empty file

What it means

This error is thrown when a .binlog file exists but has zero bytes. parse_events_from_binlog reads the whole file first and bails out early because an empty buffer cannot contain the binlog magic header, let alone any build events.

Source

Thrown at src/cmds/dotnet/binlog.rs:303

    project_files: HashSet<String>,
    errors: Vec<BinlogIssue>,
    warnings: Vec<BinlogIssue>,
    build_succeeded: Option<bool>,
    build_started_ticks: Option<i64>,
    build_finished_ticks: Option<i64>,
}

#[derive(Default)]
struct ParsedEventFields {
    message: Option<String>,
    timestamp_ticks: Option<i64>,
}

fn parse_events_from_binlog(path: &Path) -> Result<ParsedBinlog> {
    let bytes = std::fs::read(path)
        .with_context(|| format!("Failed to read binlog at {}", path.display()))?;
    if bytes.is_empty() {
        anyhow::bail!("Failed to parse binlog at {}: empty file", path.display());
    }

    let mut decoder = GzDecoder::new(bytes.as_slice());
    let mut payload = Vec::new();
    decoder.read_to_end(&mut payload).with_context(|| {
        format!(
            "Failed to parse binlog at {}: gzip decode failed",
            path.display()
        )
    })?;

    let mut reader = BinReader::new(&payload);
    let file_format_version = reader
        .read_i32_le()
        .context("binlog header missing file format version")?;
    let _minimum_reader_version = reader
        .read_i32_le()
        .context("binlog header missing minimum reader version")?;

View on GitHub (pinned to 36788f6bd4)

Solutions

  1. Delete and regenerate the binlog by re-running the build/test with /bl (or rtk's wrapping command)
  2. Check disk space and that no external process truncates the file
  3. Verify the file with `ls -l` / `wc -c` to confirm it is genuinely 0 bytes and not a path mistake
  4. Run with rtk proxy or raw dotnet to confirm the underlying build itself succeeds

Example fix

// before: parsing a possibly-empty file blindly
let binlog = parse_events_from_binlog(&path)?;
// after: guard before calling
if path.metadata()?.len() == 0 { eprintln!("binlog is empty, rerun build with /bl"); } else { let binlog = parse_events_from_binlog(&path)?; }
Defensive patterns

Strategy: validation

Validate before calling

use std::path::Path;
fn binlog_is_parseable(path: &Path) -> std::io::Result<bool> {
    Ok(path.metadata()?.len() > 0)
}

Try / catch

match parse_events_from_binlog(&path) {
    Ok(binlog) => use_events(&binlog),
    Err(e) if e.to_string().contains("empty file") => {
        eprintln!("binlog {} is empty; rerun the build with /bl", path.display());
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling rtk dotnet build/test/restore (which invoke parse_build/parse_test/parse_restore) with a .binlog path that points to a 0-byte file — e.g. the logger was attached but MSBuild crashed before writing anything, or the file was truncated by disk-full/cleanup.

Common situations: MSBuild launched with /bl but killed before flush; antivirus or a cleaner truncated the file; a wrapper script created the file but the build failed instantly; passing the wrong path variable that happens to be an empty touched file.

Understand the failure class

Related errors


AI-assisted analysis of rtk-ai/rtk@36788f6bd4 (2026-09-03). Data as JSON: /api/errors/a75d843fa110b9b8. Report an issue: GitHub.