xai-org/grok-build · error
FS_OTHER
FS_OTHER
Error message
An unexpected I/O error occurred.
What it means
A persistence I/O error did not match any classified io::ErrorKind (NotFound, PermissionDenied, StorageFull, etc.), so it falls into the catch-all arm. The library converts it into an ACP protocol error with code FS_OTHER and message 'An unexpected I/O error occurred.', while logging the raw error, kind, and raw OS error code and attaching the full detail in error data.
Source
Thrown at crates/codegen/xai-grok-shell/src/session/persistence.rs:2511
false
}
/// Map a persistence `io::Error` into an `acp::Error` with a human-friendly
/// `message` and a stable `data.code` for log aggregation.
pub(crate) fn io_error_to_acp(e: &io::Error) -> acp::Error {
let (message, code) = if is_disk_full_io_error(e) {
("No space left on device", "FS_DISK_QUOTA_EXCEEDED")
} else {
match e.kind() {
io::ErrorKind::NotFound => ("Path not found.", "FS_NOT_FOUND"),
io::ErrorKind::PermissionDenied => ("Permission denied.", "FS_PERMISSION_DENIED"),
_ => {
tracing::warn!(error = %e, kind = ?e.kind(), raw_os = ?e.raw_os_error(), "unclassified persistence I/O error");
("An unexpected I/O error occurred.", "FS_OTHER")
}
}
};
acp::Error::new(acp::ErrorCode::InternalError.into(), message.to_string()).data(Some(
serde_json::json!({
"code": code,
"detail": e.to_string(),
}),
))
}
#[cfg(test)]
#[path = "persistence_io_error_to_acp_tests.rs"]
mod io_error_to_acp_tests;
/// Best-effort worktree liveness touch: stamp `last_accessed_at` on the
/// worktree containing this session's cwd so `grok worktree gc` expires by
/// last use, not creation time. Lives here — not in a `StorageAdapter` —
/// so every session create/load path shares it regardless of backend.
fn spawn_worktree_touch(info: &Info) -> tokio::task::JoinHandle<()> {
let cwd = info.cwd.clone();
tokio::task::spawn_blocking(move || {View on GitHub (pinned to bc7f02eddd)
Solutions
- Read error.data.detail and the tracing log (kind + raw_os_error) to identify the underlying OS error
- Look up the raw OS errno (e.g. via `errno` docs) to find the real cause
- Check filesystem health/mount (dmesg, df, mount options) for the session directory volume
- Move the session directory to a local filesystem if a network mount keeps producing uncategorized errors
Defensive patterns
Strategy: try-catch
Try / catch
// ACP client side: inspect code + data.detail
if err.code == acp::ErrorCode::InternalError && err.data["code"] == "FS_OTHER" {
let detail = err.data["detail"].as_str().unwrap_or("");
tracing::error!(detail, "unclassified persistence I/O error; check raw_os_error in server logs");
// decide retry vs fail based on detail (e.g. EINTR/EAGAIN → retry, hardware → fail)
} Prevention
- Keep session data on a well-supported local filesystem, not exotic/network mounts
- Exclude session dirs from antivirus/backup lock contention
- Check disk health and quotas proactively
- Always read error.data.detail and server logs (kind + raw_os_error) — FS_OTHER hides the real errno there
When it happens
Trigger: Any append/persistence I/O operation returning an io::Error whose kind is outside the recognized set — e.g. ErrorKind::FilesystemLoop, IsADirectory, Uncategorized, or unusual errno from exotic filesystems — flowing into the error-to-ACP mapping.
Common situations: Session directory on NFS/network mounts returning unusual errnos; antivirus/backup tools locking files; odd permission setups (immutable files, selinux denials surfacing as uncategorized errors); disk quotas surfacing with unexpected kinds.
Related errors
- Failed to set working directory to {:?}: {}
- failed to save external auth credentials: {e}
- failed to read {}: {e}
- failed to write {}: {e}
- failed to create chrome trace {:?}: {}
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/ec4e3a7122b51175.
Report an issue: GitHub.