Hmbown/CodeWhale · error

hardcoded project notes state path is valid

Error message

hardcoded project notes state path is valid

What it means

Panic constructing the default `ToolContext`: `resolve_project_state_dir(&workspace, "notes.md")` (config crate, lib.rs:5827) returns `Err` when the workspace path is unusable. Its `normalize_project_workspace` (lib.rs:6652) rejects empty paths and `..` components, fails when the current directory cannot be resolved (deleted/unreadable cwd), and fails on `canonicalize` errors other than NotFound (permissions along the path). The literal subdir is always safe, so the failure is entirely about the workspace argument.

Source

Thrown at crates/tui/src/tools/spec.rs:722

    fn deref(&self) -> &Self::Target {
        &self.execution
    }
}

impl std::ops::DerefMut for ToolContext {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.execution
    }
}

impl ToolContext {
    /// Create a new `ToolContext` with default settings.
    #[must_use]
    pub fn new(workspace: impl Into<PathBuf>) -> Self {
        let workspace = workspace.into();
        // Prefer .codewhale, fall back to .deepseek for project-local state
        let notes_path = codewhale_config::resolve_project_state_dir(&workspace, "notes.md")
            .expect("hardcoded project notes state path is valid")
            .1;
        let mcp_config_path = codewhale_config::resolve_project_state_dir(&workspace, "mcp.json")
            .expect("hardcoded project MCP state path is valid")
            .1;
        Self::with_options(workspace, false, notes_path, mcp_config_path)
    }

    /// Create a `ToolContext` with all settings specified.
    #[allow(dead_code)]
    pub fn with_options(
        workspace: impl Into<PathBuf>,
        trust_mode: bool,
        notes_path: impl Into<PathBuf>,
        mcp_config_path: impl Into<PathBuf>,
    ) -> Self {
        let workspace = workspace.into();
        let shell_manager = new_shared_shell_manager(workspace.clone());
        let tool_authority = process_tool_authority();

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Pass a canonical absolute workspace path — run `std::fs::canonicalize` before constructing the context.
  2. Reject empty and `..`-containing workspace paths at your entry point with a clear error.
  3. If the cwd was deleted, restart from an existing directory.
  4. Embedders can bypass resolution entirely with `ToolContext::with_options(workspace, ..., notes_path, mcp_config_path)` using explicit paths.

Example fix

// before
let notes_path = codewhale_config::resolve_project_state_dir(&workspace, "notes.md")
    .expect("hardcoded project notes state path is valid").1;

// after: validate/canonicalize the workspace before building the ToolContext
let workspace = std::fs::canonicalize(&workspace)
    .context("workspace path must exist and be canonicalizable")?;
assert!(!workspace.components().any(|c| matches!(c, std::path::Component::ParentDir)));
Defensive patterns

Strategy: validation

Validate before calling

fn workspace_ok(ws: &std::path::Path) -> bool {
    !ws.as_os_str().is_empty()
        && !ws.components().any(|c| matches!(c, std::path::Component::ParentDir))
        && ws.canonicalize().is_ok()
}

Prevention

When it happens

Trigger: The engine or a tool constructs `ToolContext::new` with `PathBuf::new()`/`""`; a workspace containing `..` components like `"../repo"`; a process whose cwd was deleted (`failed to resolve current directory for project workspace`); permission-denied components during canonicalization.

Common situations: Embedders and tests creating `ToolContext::new(Path::new(""))`; running the TUI from a directory removed by another process; wrappers passing relative paths with `..`; permission-restricted mount points in the workspace chain.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/674942be9b79b3b8. Report an issue: GitHub.