Hmbown/CodeWhale · error

MCP config path cannot be empty

Error message

MCP config path cannot be empty

What it means

MCP config paths are validated before use; an empty path (empty OsStr) has no meaning and would break file operations downstream, so validate_mcp_config_path bails immediately. This guard runs on every MCP config load, mutation, mtime read, and workspace config-source switch.

Solutions

  1. Provide a non-empty path to your MCP config file (e.g. ~/.config/codewhale/mcp.json)
  2. Remove the empty --mcp-config flag entirely to use defaults instead of passing ""
  3. Fix the upstream substitution (env var, template) that produced the empty string

Example fix

# before
codewhale --mcp-config "" ...
# after
codewhale --mcp-config ~/.config/codewhale/mcp.json ...
Defensive patterns

Strategy: validation

Validate before calling

if (!mcpConfigPath || mcpConfigPath.trim() === "") {
  throw new Error("MCP config path must be a non-empty path");
}

Type guard

const hasMcpPath = (p: string | undefined | null): p is string =>
  typeof p === "string" && p.length > 0;

Try / catch

try {
  loadMcpConfig(pathOpt.unwrap_or_default());
} catch (e) {
  if (String(e).includes("path cannot be empty")) {
    // fall back to default mcp config location or prompt user for a path
  }
}

Prevention

When it happens

Trigger: Passing an empty string as --mcp-config or equivalent config field; a config object where the mcp config path key is present but set to ""; programmatic calls to load_config / mutate_config / switch_workspace_config_source with an empty Path.

Common situations: Environment variable or config substitution evaluating to empty string; CLI flag given as `--mcp-config ""`; templated config where the path placeholder was never filled.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

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

use crate::network_policy::{Decision, NetworkPolicyDecider, host_from_url};
use crate::utils::write_atomic;

// === Error diagnostics helpers (#71) ===

/// Bytes of a non-2xx response body to surface in connection errors.
const ERROR_BODY_PREVIEW_BYTES: usize = 200;

/// Newest dated MCP protocol revision Codewhale advertises at `initialize` and
/// answers as an MCP server. Matches the shared MCP crate (`crates/mcp`).
pub(crate) const MCP_PROTOCOL_VERSION: &str = "2025-06-18";
/// Dated MCP revisions accepted during negotiation, newest first. A peer
/// answering or requesting any of these continues the handshake.
pub(crate) const MCP_SUPPORTED_PROTOCOL_VERSIONS: &[&str] =
    &[MCP_PROTOCOL_VERSION, "2025-03-26", "2024-11-05"];

fn validate_mcp_config_path(path: &Path) -> Result<()> {
    if path.as_os_str().is_empty() {
        anyhow::bail!("MCP config path cannot be empty");
    }
    if path
        .components()
        .any(|component| matches!(component, Component::ParentDir))
    {
        anyhow::bail!("MCP config path cannot contain '..' components");
    }
    Ok(())
}

/// Expand `${NAME}` placeholders in an MCP config value from the process
/// environment. This lets secrets (API keys, bearer tokens, …) be supplied
/// through environment variables instead of being written in cleartext into
/// the MCP config file on disk.
///
/// On a missing or malformed placeholder the error names only the offending
/// variable, never the surrounding value, so a secret-bearing string is never
/// echoed into logs or error output.

View on GitHub (pinned to 73e0f67d83)