{"record":{"id":"58110bb665ec5ed8","repo":"Hmbown/CodeWhale","slug":"workspace-snapshots-are-disabled-for-reason","errorCode":null,"errorMessage":"workspace snapshots are disabled for {reason}: {}","messagePattern":"workspace snapshots are disabled for (.+?): (.+?)","errorType":"validation","errorClass":"std::io::Error","httpStatus":null,"severity":"warning","filePath":"crates/tui/src/snapshot/repo.rs","lineNumber":238,"sourceCode":"    }\n\n    /// Variant of [`Self::open_or_init`] that accepts an explicit\n    /// workspace-size cap. `cap_bytes = 0` disables the cap entirely\n    /// (always snapshot, regardless of size).\n    ///\n    /// When the workspace exceeds the cap and the side repo hasn't\n    /// been initialized yet, returns `Err(InvalidInput)` with a\n    /// \"workspace too large\" reason. Subsequent calls (after the user\n    /// shrinks the workspace or raises the cap via config) succeed.\n    pub fn open_or_init_with_cap(workspace: &Path, cap_bytes: u64) -> io::Result<Self> {\n        let work_tree = workspace\n            .canonicalize()\n            .unwrap_or_else(|_| workspace.to_path_buf());\n        if let Some(reason) = unsafe_workspace_snapshot_reason(\n            &work_tree,\n            crate::config::effective_home_dir().as_deref(),\n        ) {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidInput,\n                format!(\n                    \"workspace snapshots are disabled for {reason}: {}\",\n                    work_tree.display()\n                ),\n            ));\n        }\n\n        let _ = ensure_snapshot_dir(&work_tree)?;\n        let git_dir = snapshot_git_dir(&work_tree);\n\n        let needs_init = !git_dir.exists();\n        if needs_init {\n            // First-init size guard. Skipping this on subsequent opens\n            // is intentional: paying a workspace walk on every snapshot\n            // would defeat the purpose of the cap, and a workspace\n            // that fit on first init is allowed to grow within the\n            // existing repo's `MAX_SNAPSHOT_SIZE_MB` budget. Users on","sourceCodeStart":220,"sourceCodeEnd":256,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/snapshot/repo.rs#L220-L256","documentation":"open_or_init_with_cap refuses InvalidInput to create a workspace snapshot repo when the workspace is one Codewhale deliberately will not snapshot: the filesystem root, the user's home directory itself, or a well-known home collection directory (Desktop, Documents, Downloads, Library, Movies, Music, Pictures directly under home). This is a hard safety guard against sweeping an entire disk/home into git; unlike the size cap it has no config override.","triggerScenarios":"Starting Codewhale with workspace canonicalizing to \"/\", to $HOME, or to $HOME/Documents (or another listed collection dir) while no side snapshot repo exists yet at snapshot_git_dir(work_tree).","commonSituations":"Launching from a fresh shell still in $HOME without cd into a project; GUI launchers whose default working directory is home; scripts or containers that intentionally run at /; symlinks that canonicalize a project path back into home.","solutions":["cd into the actual project directory and relaunch so the workspace is a normal subdirectory","If you really want that tree snapshotted, point the workspace at a dedicated subdirectory under it (e.g. ~/work/proj, not ~/Documents)","Do not look for a config flag — this refusal is by design (unsafe_workspace_snapshot_reason), not a tunable cap"],"exampleFix":"// before\n$ codewhale --workspace ~        // Err: workspace snapshots are disabled for home directory\n\n// after\n$ codewhale --workspace ~/src/myapp   // normal project dir, snapshots init fine","handlingStrategy":"validation","validationCode":"fn snapshot_safe_workspace(ws: &std::path::Path) -> bool {\n    let canon = ws.canonicalize().unwrap_or_else(|_| ws.to_path_buf());\n    if canon.parent().is_none() { return false; }                       // filesystem root\n    if let Ok(home) = std::env::var(\"HOME\") {\n        let home = std::path::Path::new(&home).canonicalize().unwrap_or_else(|_| std::path::PathBuf::from(&home));\n        if canon == home { return false; }                               // home itself\n        if canon.parent() == Some(home.as_path()) {\n            if let Some(n) = canon.file_name().and_then(|n| n.to_str()) {\n                if matches!(n, \"Desktop\"|\"Documents\"|\"Downloads\"|\"Library\"|\"Movies\"|\"Music\"|\"Pictures\") {\n                    return false;                                        // home collection dir\n                }\n            }\n        }\n    }\n    true\n}","typeGuard":"fn is_unsafe_workspace_error(e: &std::io::Error) -> bool {\n    e.kind() == std::io::ErrorKind::InvalidInput && e.to_string().contains(\"snapshots are disabled for\")\n}","tryCatchPattern":null,"preventionTips":["Always launch from the project directory, never from $HOME or /","In scripts, assert the workspace is a non-home subdirectory before enabling snapshots","Remember this guard is intentional and has no config override"],"tags":["snapshots","workspace","path-safety","config","rust"],"backgroundTag":"protected-directory-rejection","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}