Hmbown/CodeWhale · error
MCP pool has no configuration source to reload
Error message
MCP pool has no configuration source to reload
What it means
`reload_from_config_sources(force = true)` was called but the pool has no recorded configuration sources, so there is nothing to reload. The non-forced path silently returns `Ok(false)`; only an explicit forced reload errors, because the caller demanded a reload that cannot happen.
Solutions
- Construct the pool via `from_config_path*` so `config_sources` is populated.
- Only call the forced reload when `config_sources` is non-empty; use the non-forced check otherwise.
- If the pool is intentionally file-less, remove it from the reload loop instead of force-reloading.
Example fix
// before
pool.reload_from_config_sources(true)?; // panics/errors when no sources
// after
if pool.has_config_sources() {
pool.reload_from_config_sources(true)?;
} Defensive patterns
Strategy: type-guard
Validate before calling
if pool.config_sources.is_empty() {
// nothing to reload; skip instead of forcing
return Ok(false);
} Type guard
fn reloadable(pool: &McpPool) -> bool { !pool.config_sources.is_empty() } Try / catch
match pool.reload_from_config_sources(force) {
Err(e) if e.to_string().contains("no configuration source to reload") => Ok(false),
other => other,
} Prevention
- Build pools that need hot-reload via from_config_path* so config_sources is set.
- Only pass force=true from explicit user reload actions, not from watch loops.
- Exclude programmatically-configured pools from file-watch reload registries.
When it happens
Trigger: Calling a forced config reload (hot-reload / manual reload API) on an `McpPool` built without `config_sources` (e.g. via `McpConfig::default()` without `from_config_path*`).
Common situations: Programmatically constructed pools (no config file) hooked into a file-watcher reload loop; calling force-reload after sources were cleared.
Understand the failure class
Background: "missing required config value" errors: why libraries refuse to start when a configuration key is empty, unset, or blank — this error's family across 48 libraries.
Related errors
- Failed to connect MCP server
- Failed to find MCP server
- MCP server ' ' has no command configured
- MCP server ' ' has no command configured
- MCP server ' ' is disabled
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/57546bba273a2b00.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/mcp.rs:3028
}
/// If the source config file's mtime has changed since the last check,
/// re-read it and (only when the content hash also changed) drop all
/// existing connections so the next `get_or_connect` reattaches under
/// the new config. No-op when the pool was constructed via [`McpPool::new`]
/// (no source path), when stat fails, or when the file content is
/// byte-identical to what we last loaded. Returns `Ok(true)` if any
/// connections were dropped, `Ok(false)` otherwise.
///
/// This is the lazy half of the auto-reload story for #1267: instead of a
/// long-lived file watcher, the next tool invocation pays a single `stat`
/// call (and only re-reads the file when the mtime moved). On networked
/// or remote filesystems where mtime granularity is poor, the hash
/// compare keeps us from churning connections on every check.
fn reload_from_config_sources(&mut self, force: bool) -> Result<bool> {
if self.config_sources.is_empty() {
if force {
anyhow::bail!("MCP pool has no configuration source to reload");
}
return Ok(false);
}
let current_mtimes: Vec<_> = self
.config_sources
.iter()
.map(|path| mcp_config_mtime(path))
.collect();
if !force && current_mtimes == self.last_mtimes {
return Ok(false);
}
// An mtime moved, or the user explicitly requested a reload: re-read
// the complete global + workspace + plugin-backed config.
let primary = self
.config_sources
.first()
.context("MCP config source list unexpectedly empty")?;
let new_config = if let Some(workspace) = self.workspace.as_deref() {View on GitHub (pinned to 73e0f67d83)