xai-org/grok-build · error · std::io::Error
workflow artifact exceeds {limit} bytes: {}
Error message
workflow artifact exceeds {limit} bytes: {} What it means
read_bounded_nofollow enforces a maximum artifact size. If symlink_metadata reports the file is larger than `limit` before opening, it returns InvalidData with this message to avoid unbounded memory use when loading run state.
Source
Thrown at crates/codegen/xai-grok-shell/src/session/workflow/store.rs:319
}
pub(crate) fn script_revision_path(run_dir: &Path, revision: u32) -> PathBuf {
run_dir.join("scripts").join(format!("{revision:04}.rhai"))
}
pub(crate) fn read_bounded_nofollow(path: &Path, limit: u64) -> io::Result<Vec<u8>> {
let metadata = std::fs::symlink_metadata(path)?;
if metadata.file_type().is_symlink() || !metadata.is_file() {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"workflow artifact is not a regular file: {}",
path.display()
),
));
}
if metadata.len() > limit {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"workflow artifact exceeds {limit} bytes: {}",
path.display()
),
));
}
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() > limit {
return Err(io::Error::new(View on GitHub (pinned to bc7f02eddd)
Solutions
- Raise the artifact size limit to a value that accommodates legitimate run state
- Inspect and truncate/compact the oversized artifact, then re-persist it
- Delete the corrupt/oversized run directory and re-register the run
- Find what wrote unbounded data (missing bounds in a writer) and fix it
Example fix
// before let bytes = store.read_bounded_nofollow(&path, 1024)?; // legit manifest is 4 KB // after const MAX_RUN_MANIFEST: u64 = 64 * 1024; let bytes = store.read_bounded_nofollow(&path, MAX_RUN_MANIFEST)?;
Defensive patterns
Strategy: try-catch
Validate before calling
fn within_limit(p: &std::path::Path, limit: u64) -> bool {
std::fs::symlink_metadata(p).map(|m| m.len() <= limit).unwrap_or(false)
} Try / catch
match store.read_bounded_nofollow(&path, limit) {
Ok(bytes) => Ok(bytes),
Err(e) if e.kind() == std::io::ErrorKind::InvalidData
&& e.to_string().contains("exceeds") => {
// compact or quarantine the oversized run, do not retry blindly
quarantine_run_dir(&run_dir)?;
Ok(Vec::new())
}
Err(e) => Err(e.into()),
} Prevention
- Set the artifact limit comfortably above real manifest sizes and document it
- Compact run state periodically instead of appending forever
- Never write log-like unbounded data into workflow artifacts
- Alert when a load rejects an artifact — it usually means a corrupt writer
When it happens
Trigger: A workflow artifact (runs.json or a .rhai script) exceeds the configured byte limit at load time in load_workflow_runs_sync — e.g. corrupted writer, huge injected file, or a too-small limit for legitimately large runs.
Common situations: Run manifest grown beyond expectations after many updates; maliciously planted oversized file in the runs dir; operator lowered the limit after old runs already exceed it.
Related errors
- workflow artifact is not a regular file: {}
- workflow artifact changed during open: {}
- decoded artifact exceeds the {MAX_DECODED_BYTES}-byte cap
- Failed to set working directory to {:?}: {}
- Failed to load config: {e}
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/fc5cb063e501b2cc.
Report an issue: GitHub.