{"record":{"id":"6a53c115b7d47a49","repo":"astrid-runtime/astrid","slug":"no-cow-workspace-does-not-support-rollback","errorCode":null,"errorMessage":"No-CoW workspace does not support rollback","messagePattern":"No-CoW workspace does not support rollback","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/astrid-vfs/src/workspace_cow/mod.rs","lineNumber":163,"sourceCode":"    }\n\n    fn promote(&self) -> io::Result<()> {\n        tracing::warn!(\n            \"workspace CoW: promote requested on a No-CoW workspace — writes already \\\n             went direct to the workspace, there is nothing to commit\"\n        );\n        Err(io::Error::new(\n            io::ErrorKind::Unsupported,\n            \"No-CoW workspace does not support promote\",\n        ))\n    }\n\n    fn rollback(&self) -> io::Result<()> {\n        tracing::warn!(\n            \"workspace CoW: rollback requested on a No-CoW workspace — writes already \\\n             went direct to the workspace and cannot be rolled back\"\n        );\n        Err(io::Error::new(\n            io::ErrorKind::Unsupported,\n            \"No-CoW workspace does not support rollback\",\n        ))\n    }\n\n    fn teardown(&self) {}\n}\n\n/// Construct the preferred copy-on-write backend for this host, storing its\n/// working trees under caller-selected disposable scratch (the capsule runtime\n/// uses the boot-cleaned `run/hosted-workspace-cow` tree).\n///\n/// The factory only *selects* a backend; the mount/clone happens in\n/// [`prepare`](WorkspaceCow::prepare). Selection order:\n/// * macOS → [`ApfsCow`](apfs::ApfsCow).\n/// * Linux → `OverlayfsCow` (which tries a native `overlayfs` mount, then\n///   `fuse-overlayfs`, at prepare time).\n/// * any other platform → [`NoCow`], with a `warn` naming the reason.","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-vfs/src/workspace_cow/mod.rs#L145-L181","documentation":"The No-CoW workspace strategy writes directly to the workspace, so no staged changes exist to discard. rollback on this backend deliberately returns an Unsupported error instead of pretending to undo writes that already landed in the workspace.","triggerScenarios":"Calling rollback() on a workspace running the No-CoW strategy (CoW unavailable or disabled), typically from an error-handling path that assumes staged writes.","commonSituations":"Generic error-recovery code that unconditionally calls rollback; environments where clonefile is unavailable so the backend silently fell back to No-CoW; CoW disabled in deployment config.","solutions":["Only call rollback when the workspace is in CoW mode; check the strategy first","Enable CoW (APFS clonefile-capable volume, feature enabled) if rollback semantics are required","Accept that with No-CoW, writes are already durable and cannot be undone — compensate at a higher level","Treat io::ErrorKind::Unsupported from rollback as 'nothing to roll back' in generic recovery code"],"exampleFix":"// before\nif let Err(e) = task { workspace.rollback()?; }\n// after\nif let Err(e) = task {\n    if workspace.supports_cow() {\n        workspace.rollback()?;\n    } else {\n        tracing::warn!(\"No-CoW workspace: cannot roll back, writes were direct\");\n    }\n}","handlingStrategy":"type-guard","validationCode":"fn rollback_if_cow(ws: &dyn WorkspaceBackend) -> io::Result<()> {\n    if ws.strategy() == Strategy::NoCow {\n        tracing::warn!(\"No-CoW: nothing to roll back\");\n        return Ok(());\n    }\n    ws.rollback()\n}","typeGuard":"fn supports_rollback(ws: &dyn WorkspaceBackend) -> bool {\n    ws.strategy() != Strategy::NoCow\n}","tryCatchPattern":"match ws.rollback() {\n    Err(e) if e.kind() == io::ErrorKind::Unsupported => {\n        tracing::warn!(\"No-CoW workspace: writes cannot be rolled back\");\n        // escalate: manual cleanup or compensation at a higher level\n        Ok(())\n    }\n    other => other,\n}","preventionTips":["Check the workspace strategy before attempting rollback in error handlers","Never assume staged-write semantics — the backend may be No-CoW","If atomicity matters, require CoW at startup and refuse No-CoW fallback","Design compensating actions for No-CoW failures since writes are already durable"],"tags":["cow","workspace","unsupported","rollback"],"backgroundTag":"unsupported-operation","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}