xai-org/grok-build · warning · std::io::Error
<invalid u64 in memory.current>
Error message
<invalid u64 in memory.current>
What it means
memory_current reads the cgroup's memory.current file and parses its trimmed contents as u64; if the parse fails it wraps the ParseIntError in an io::Error with InvalidData. The message "<invalid u64 in memory.current>" indicates the kernel-reported value could not be interpreted as an unsigned 64-bit integer.
Source
Thrown at crates/codegen/xai-grok-tools/src/computer/local/cgroup.rs:243
"Created cgroup with memory limits"
);
Ok(CgroupHandle { fs_path })
}
/// Move a process (by PID) into this cgroup.
pub(crate) async fn add_process(&self, pid: u32) -> std::io::Result<()> {
let procs_path = self.fs_path.join("cgroup.procs");
tokio::fs::write(&procs_path, pid.to_string()).await
}
/// Read `memory.current` from this cgroup.
#[allow(dead_code)]
pub(crate) async fn memory_current(&self) -> std::io::Result<u64> {
let s: String = tokio::fs::read_to_string(self.fs_path.join("memory.current")).await?;
s.trim()
.parse::<u64>()
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))
}
/// Filesystem path to this cgroup.
pub(crate) fn path(&self) -> &std::path::Path {
&self.fs_path
}
}
impl Drop for CgroupHandle {
fn drop(&mut self) {
let path = self.fs_path.clone();
// Always use tokio::spawn: the cleanup future is Send and Drop
// can fire after the LocalSet has shut down, making spawn_local
// unsafe here.
tokio::spawn(async move {
let kill_path = path.join("cgroup.kill");
let _ = tokio::fs::write(&kill_path, "1").await;
tokio::time::sleep(std::time::Duration::from_millis(50)).await;View on GitHub (pinned to bc7f02eddd)
Solutions
- Verify fs_path points to an actual cgroupv2 directory containing a valid memory.current file.
- cat the file manually to inspect its contents for non-numeric values like "max" or empty output.
- Add a fallback (return None / a sentinel) when parsing fails so monitoring code treats it as an unreadable gauge rather than an error.
- Retry after a short delay if the cgroup is being created/destroyed concurrently.
Example fix
// before
let bytes = cgroup.memory_current()?;
// after
let bytes = match cgroup.memory_current() {
Ok(b) => b,
Err(e) if e.kind() == std::io::ErrorKind::InvalidData => {
tracing::warn!("memory.current unreadable; skipping sample");
0
}
Err(e) => return Err(e),
}; Defensive patterns
Strategy: try-catch
Validate before calling
let raw = tokio::fs::read_to_string(cgroup.path().join("memory.current")).await?;
let valid = raw.trim().parse::<u64>().is_ok(); Try / catch
match cgroup.memory_current().await {
Ok(v) => v,
Err(e) if e.kind() == std::io::ErrorKind::InvalidData => 0, // skip sample
Err(e) => return Err(e.into()),
} Prevention
- Confirm the cgroup path is a real cgroupv2 directory before sampling.
- Sanitize/guard metrics values so non-numeric states are reported as unavailable.
- Log the raw file contents when parsing fails to ease diagnosis.
- Poll memory.events/memory.current only after the cgroup is fully created.
When it happens
Trigger: memory.current containing "max", an empty string, or non-numeric bytes — e.g. reading from a wrong/placeholder cgroup path, a mocked or virtualized filesystem, or a file truncated to garbage.
Common situations: Pointing fs_path at a directory that is not a real cgroup; tests stubbing memory.current with placeholder text; container runtimes exposing nonstandard cgroup files; race where the cgroup directory is being torn down and reads return partial data.
Related errors
- Could not find cgroupv2 entry in /proc/self/cgroup
- unix socket path too long: {}
- unmount {}: {err}
- no clipboard backend available
- arboard leg disabled (GROK_CLIPBOARD_NO_DATA_CONTROL)
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/1089d6a885c07918.
Report an issue: GitHub.