Hmbown/CodeWhale · error

hardcoded project MCP state path is valid

Error message

hardcoded project MCP state path is valid

What it means

Panic constructing the default `ToolContext`, sibling of the notes-path expect two lines above: `resolve_project_state_dir(&workspace, "mcp.json")` fails for the same workspace-path reasons (empty path, `..` components, unresolvable cwd, non-NotFound canonicalize error). In practice the `notes.md` call at spec.rs:722 runs first, so hitting this exact line means the notes path resolved but the MCP path did not — only possible if intermediate filesystem state changed between the two calls (e.g. permissions altered or the workspace unmounted mid-construction).

Source

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

}

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();
        let shell_policy = match tool_authority.as_deref() {
            Some(cap) => cap.shell.shell_policy(),
            None => ShellPolicy::Full,

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Pass a canonical absolute workspace path and construct the context once, early, before long-running turns.
  2. Reject empty and `..`-containing workspace paths at your entry point.
  3. Check permissions on every component of the workspace chain (`namei -l <workspace>` helps on Linux).
  4. Use `ToolContext::with_options` with explicit, pre-validated paths when embedding.

Example fix

// before
let mcp_config_path = codewhale_config::resolve_project_state_dir(&workspace, "mcp.json")
    .expect("hardcoded project MCP state path is valid").1;

// after: resolve both state paths once, with a clear failure
let (notes_path, mcp_config_path) = (
    codewhale_config::resolve_project_state_dir(&workspace, "notes.md")
        .context("resolve project notes state path")?.1,
    codewhale_config::resolve_project_state_dir(&workspace, "mcp.json")
        .context("resolve project MCP state path")?.1,
);
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: Same as the notes-path variant: `ToolContext::new("")`, relative workspace with `..`, deleted cwd, permission failures — plus the narrow race where `.codewhale/`/`.deepseek/` state resolution succeeds for notes.md but the filesystem rejects the second lookup.

Common situations: Embedders/tests with degenerate workspace paths; filesystems being remounted or permission changes racing tool-context construction; NFS/FUSE mounts with intermittent EACCES.

Related errors


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