Hmbown/CodeWhale · error · std::io::Error

workspace snapshots are disabled for

Error message

workspace snapshots are disabled for {reason}: {workspace}

What it means

open_or_init_with_cap checks the workspace via unsafe_workspace_snapshot_reason before opening/initializing the snapshot repo. If the work tree is in an unsafe location (e.g. inside the user's effective home directory), it refuses with ErrorKind::InvalidInput, prefixing GATE_UNSAFE_LOCATION_MARKER so callers can detect the gate.

Solutions

  1. Run from a dedicated project directory instead of the home directory.
  2. Inspect the reason in the message ('for {reason}: {workspace}') and move the offending path out of the gated location.
  3. If symlinks cause it, resolve/adjust the symlink so the canonical path is a normal project directory.

Example fix

// before
cd ~ && codewhale            // gated: workspace == home
// after
cd ~/projects/myapp && codewhale
Defensive patterns

Strategy: validation

Validate before calling

let canon = std::fs::canonicalize(workspace).unwrap_or_else(|_| workspace.into());
let home = dirs::home_dir().unwrap();
if canon.starts_with(&home) && canon != home.join("projects") { eprintln!("workspace inside home is gated for snapshots"); }

Try / catch

match open_or_init_with_cap(ws, cap) {
    Err(e) if e.to_string().contains(GATE_UNSAFE_LOCATION_MARKER) => eprintln!("run from a project directory outside ~"),
    r => r?,
}

Prevention

When it happens

Trigger: Calling open_or_init_with_cap with a workspace that canonicalizes to a dangerous location such as the home directory itself or a path containing the home dir, per unsafe_workspace_snapshot_reason.

Common situations: Launching codewhale with the working directory set to ~ or a mount that canonicalizes into ~; symlinked project paths resolving into the home directory.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/db7135046affde95. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/snapshot/repo.rs:324

    }

    /// Variant of [`Self::open_or_init`] that accepts an explicit
    /// workspace-size cap. `cap_bytes = 0` disables the cap entirely
    /// (always snapshot, regardless of size).
    ///
    /// When the workspace exceeds the cap and the side repo hasn't
    /// been initialized yet, returns `Err(InvalidInput)` with a
    /// "workspace too large" reason. Subsequent calls (after the user
    /// shrinks the workspace or raises the cap via config) succeed.
    pub fn open_or_init_with_cap(workspace: &Path, cap_bytes: u64) -> io::Result<Self> {
        let work_tree = workspace
            .canonicalize()
            .unwrap_or_else(|_| workspace.to_path_buf());
        if let Some(reason) = unsafe_workspace_snapshot_reason(
            &work_tree,
            crate::config::effective_home_dir().as_deref(),
        ) {
            return Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                format!(
                    "{GATE_UNSAFE_LOCATION_MARKER} for {reason}: {}",
                    display_workspace_for_gate(workspace)
                ),
            ));
        }

        let _ = ensure_snapshot_dir(&work_tree)?;
        let git_dir = snapshot_git_dir(&work_tree);

        let needs_init = !git_dir.exists();
        if needs_init {
            // First-init size guard. Skipping this on subsequent opens
            // is intentional: paying a workspace walk on every snapshot
            // would defeat the purpose of the cap, and a workspace
            // that fit on first init is allowed to grow within the
            // existing repo's `MAX_SNAPSHOT_SIZE_MB` budget. Users on

View on GitHub (pinned to 433685b202)