Hmbown/CodeWhale · error

active plugin registry is missing its pre-dotenv environment

Error message

active plugin registry is missing its pre-dotenv environment snapshot

What it means

When merging plugin-contributed MCP servers, the manager needs the process environment as it was before any dotenv/.env overlays were applied, so plugin servers get the host environment rather than project-scoped values. That snapshot (registry.host_environment()) is captured when the plugin registry is built; if it is absent the merge fails on this invariant instead of silently using the wrong environment.

Source

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

fn merge_plugin_mcp_servers(
    config: McpConfig,
    registry: &crate::plugins::PluginRegistry,
) -> Result<McpConfig> {
    let Some(state_path) = registry.state_path().map(Path::to_path_buf) else {
        return Ok(config);
    };
    let plugins = registry
        .active_plugins()
        .into_iter()
        .filter_map(|plugin| {
            plugin
                .authority(state_path.clone(), registry.workspace().to_path_buf())
                .map(|authority| (plugin.name().to_string(), plugin.clone(), authority))
        })
        .collect::<Vec<_>>();

    let host_environment = registry.host_environment().ok_or_else(|| {
        anyhow::anyhow!("active plugin registry is missing its pre-dotenv environment snapshot")
    })?;
    merge_plugin_mcp_servers_from_plugins_with_environment(config, plugins, host_environment)
}

fn merge_plugin_mcp_servers_from_plugins_with_environment(
    mut config: McpConfig,
    plugins: impl IntoIterator<
        Item = (
            String,
            crate::plugins::types::LoadedPlugin,
            crate::plugins::types::PluginAuthority,
        ),
    >,
    host_environment: Arc<crate::plugins::HostEnvironment>,
) -> Result<McpConfig> {
    for (plugin_name, plugin, authority) in plugins {
        // Adapter-level denial keeps headless paths fail-closed even if a
        // future caller accidentally passes the full inventory instead of the

View on GitHub (pinned to 8880682c63)

Solutions

  1. Build the registry through the normal bootstrap API that snapshots the pre-dotenv environment
  2. Update codewhale so all crates are the same version and the registry always records host_environment
  3. If this reproduces with the standard bootstrap, file a bug - the invariant should always hold
Defensive patterns

Strategy: validation

Validate before calling

// Verify the invariant before merging plugin MCP servers:
if registry.host_environment().is_none() {
    anyhow::bail!("registry built without pre-dotenv snapshot; rebuild it via the standard bootstrap");
}
merge_plugin_mcp_servers(&mut config, &registry)?;

Try / catch

match merge_plugin_mcp_servers(&mut config, &registry) {
    Err(e) if e.to_string().contains("pre-dotenv environment snapshot") => {
        // rebuild the registry through the supported constructor and retry once
    }
    other => other,
}

Prevention

When it happens

Trigger: Calling merge_plugin_mcp_servers (directly or via manager bootstrap) with a registry constructed without capturing the pre-dotenv environment - e.g. a custom or test-built registry using a lower-level constructor, or version skew after an upgrade.

Common situations: Upgrading to a version where registry construction changed; embedding the registry in tests or external tools that bypass the standard bootstrap path.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16). Data as JSON: /api/errors/42611e8450bed454. Report an issue: GitHub.