xai-org/grok-build · error · io::Error

journal exceeds {MAX_JOURNAL_BYTES} bytes

Error message

journal exceeds {MAX_JOURNAL_BYTES} bytes

What it means

read_journal_bounded enforces a maximum journal size (MAX_JOURNAL_BYTES) before opening the file, rejecting oversized journals with io::ErrorKind::InvalidData. This bounds memory usage and load time when loading a journal, protecting against runaway or corrupt journals.

Source

Thrown at crates/codegen/xai-workflow/src/journal.rs:264

            truncate_tail(path, new_len)?;
        }
        self.entries.pop();
        self.bytes = new_len;
        self.last_line_start = None;
        Ok(true)
    }
}

fn read_journal_bounded(path: &Path) -> std::io::Result<Vec<u8>> {
    let metadata = std::fs::symlink_metadata(path)?;
    if metadata.file_type().is_symlink() || !metadata.is_file() {
        return Err(std::io::Error::new(
            std::io::ErrorKind::InvalidData,
            format!("journal is not a regular file: {}", path.display()),
        ));
    }
    if metadata.len() > MAX_JOURNAL_BYTES {
        return Err(std::io::Error::new(
            std::io::ErrorKind::InvalidData,
            format!("journal exceeds {MAX_JOURNAL_BYTES} bytes"),
        ));
    }
    let mut options = std::fs::OpenOptions::new();
    options.read(true);
    #[cfg(unix)]
    {
        use std::os::unix::fs::OpenOptionsExt;
        options.custom_flags(libc::O_NOFOLLOW);
    }
    let file = options.open(path)?;
    let opened = file.metadata()?;
    if !opened.is_file() || opened.len() > MAX_JOURNAL_BYTES {
        return Err(std::io::Error::new(
            std::io::ErrorKind::InvalidData,
            "journal changed during open",
        ));

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. Rotate or truncate the journal: archive the old file and start fresh (the workflow will resume with an empty journal)
  2. Compact/rewrite the journal keeping only the latest state per record
  3. Increase MAX_JOURNAL_BYTES if the workload legitimately needs larger journals and memory permits

Example fix

# archive the oversized journal and let the library start a new one
mv journal journal.old.1 && touch journal
Defensive patterns

Strategy: try-catch

Validate before calling

fn journal_size_ok(path: &Path) -> std::io::Result<bool> {
    Ok(std::fs::metadata(path)?.len() <= MAX_JOURNAL_BYTES)
}
if journal_size_ok(&journal_path).unwrap_or(true) {
    load(&journal_path)?;
} else {
    std::fs::rename(&journal_path, journal_path.with_extension("old"))?;
}

Try / catch

if let Err(e) = load(&journal_path) {
    if e.kind() == std::io::ErrorKind::InvalidData {
        // journal exceeds the size cap: archive it and start fresh
        std::fs::rename(&journal_path, journal_path.with_extension("old"))?;
        load(&journal_path)?;
    } else { return Err(e.into()); }
}

Prevention

When it happens

Trigger: Loading a journal whose file length exceeds MAX_JOURNAL_BYTES — typically after a very long-running workflow accumulated records, or a corrupted/appending-wrong-data journal grew unboundedly.

Common situations: Long-lived workflow processes appending for weeks without rotation/compaction; a bug causing repeated identical records; a foreign large file placed at the journal path.

Related errors


AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31). Data as JSON: /api/errors/410d8ec784f6b73d. Report an issue: GitHub.