Hmbown/CodeWhale · error

plugin registry workspace does not match MCP pool workspace

Error message

plugin registry workspace does not match MCP pool workspace

What it means

`McpPool::from_config_path_with_workspace_and_plugins` requires that the supplied `PluginRegistry` was constructed for exactly the same workspace path being given to the pool. A mismatch means config loads and plugin enumeration would disagree about the workspace, so the constructor refuses up front.

Solutions

  1. Pass the same workspace path the PluginRegistry was built with (compare canonicalized paths).
  2. Rebuild the PluginRegistry with `PluginRegistry::new(<workspace>)` for this workspace before constructing the pool.
  3. Canonicalize both paths (e.g. `std::fs::canonicalize`) before comparing to avoid symlink/relative mismatches.

Example fix

// before
let plugins = PluginRegistry::new(&other_workspace);
McpPool::from_config_path_with_workspace_and_plugins(&path, &workspace, plugins)?
// after
let plugins = PluginRegistry::new(&workspace);
McpPool::from_config_path_with_workspace_and_plugins(&path, &workspace, plugins)?
Defensive patterns

Strategy: validation

Validate before calling

let ws_canon = std::fs::canonicalize(workspace)?;
let reg_canon = std::fs::canonicalize(plugins.workspace())?;
assert_eq!(ws_canon, reg_canon, "registry workspace must equal pool workspace");

Prevention

When it happens

Trigger: Calling `from_config_path_with_workspace_and_plugins(path, workspace, plugins)` where `plugins.workspace() != workspace` (different `Path` values, including non-canonicalized variants).

Common situations: Passing a registry built for a different project directory, comparing unsymlinked vs resolved paths, or a relative vs absolute path mix-up.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/d467d41950a97359. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/mcp.rs:2839

    /// Create a pool from global MCP config plus workspace-local
    /// `.codewhale/mcp.json`. Project servers override same-name global
    /// servers and default stdio `cwd` to the workspace root.
    #[cfg(test)]
    pub fn from_config_path_with_workspace(
        path: &std::path::Path,
        workspace: &Path,
    ) -> Result<Self> {
        let plugins = Arc::new(crate::plugins::PluginRegistry::empty(workspace));
        Self::from_config_path_with_workspace_and_plugins(path, workspace, plugins)
    }

    pub fn from_config_path_with_workspace_and_plugins(
        path: &std::path::Path,
        workspace: &Path,
        plugins: Arc<crate::plugins::PluginRegistry>,
    ) -> Result<Self> {
        if plugins.workspace() != workspace {
            anyhow::bail!("plugin registry workspace does not match MCP pool workspace");
        }
        let config = load_config_with_workspace_and_plugins(path, workspace, plugins.as_ref())?;
        let workspace = checked_workspace_path(workspace)?;
        let mut pool = Self::new(config);
        pool.config_sources = vec![
            path.to_path_buf(),
            checked_workspace_mcp_config_path(&workspace)?,
        ];
        pool.config_sources
            .extend(crate::config::workspace_trust_config_candidate_paths());
        pool.last_mtimes = pool
            .config_sources
            .iter()
            .map(|source| mcp_config_mtime(source))
            .collect();
        pool.workspace = Some(workspace);
        pool.plugin_registry = Some(plugins);
        Ok(pool)

View on GitHub (pinned to 73e0f67d83)