{"record":{"id":"ec4e3a7122b51175","repo":"xai-org/grok-build","slug":"fs-other","errorCode":"FS_OTHER","errorMessage":"An unexpected I/O error occurred.","messagePattern":"An unexpected I/O error occurred\\.","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-shell/src/session/persistence.rs","lineNumber":2511,"sourceCode":"    false\n}\n\n/// Map a persistence `io::Error` into an `acp::Error` with a human-friendly\n/// `message` and a stable `data.code` for log aggregation.\npub(crate) fn io_error_to_acp(e: &io::Error) -> acp::Error {\n    let (message, code) = if is_disk_full_io_error(e) {\n        (\"No space left on device\", \"FS_DISK_QUOTA_EXCEEDED\")\n    } else {\n        match e.kind() {\n            io::ErrorKind::NotFound => (\"Path not found.\", \"FS_NOT_FOUND\"),\n            io::ErrorKind::PermissionDenied => (\"Permission denied.\", \"FS_PERMISSION_DENIED\"),\n            _ => {\n                tracing::warn!(error = %e, kind = ?e.kind(), raw_os = ?e.raw_os_error(), \"unclassified persistence I/O error\");\n                (\"An unexpected I/O error occurred.\", \"FS_OTHER\")\n            }\n        }\n    };\n    acp::Error::new(acp::ErrorCode::InternalError.into(), message.to_string()).data(Some(\n        serde_json::json!({\n            \"code\": code,\n            \"detail\": e.to_string(),\n        }),\n    ))\n}\n\n#[cfg(test)]\n#[path = \"persistence_io_error_to_acp_tests.rs\"]\nmod io_error_to_acp_tests;\n\n/// Best-effort worktree liveness touch: stamp `last_accessed_at` on the\n/// worktree containing this session's cwd so `grok worktree gc` expires by\n/// last use, not creation time. Lives here — not in a `StorageAdapter` —\n/// so every session create/load path shares it regardless of backend.\nfn spawn_worktree_touch(info: &Info) -> tokio::task::JoinHandle<()> {\n    let cwd = info.cwd.clone();\n    tokio::task::spawn_blocking(move || {","sourceCodeStart":2493,"sourceCodeEnd":2529,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-shell/src/session/persistence.rs#L2493-L2529","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// ACP client side: inspect code + data.detail\nif err.code == acp::ErrorCode::InternalError && err.data[\"code\"] == \"FS_OTHER\" {\n    let detail = err.data[\"detail\"].as_str().unwrap_or(\"\");\n    tracing::error!(detail, \"unclassified persistence I/O error; check raw_os_error in server logs\");\n    // decide retry vs fail based on detail (e.g. EINTR/EAGAIN → retry, hardware → fail)\n}","preventionTips":["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"],"tags":["io","filesystem","acp","unclassified","persistence"],"backgroundTag":"unclassified-io-error","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}