Hmbown/CodeWhale · error · anyhow::Error

active plugin registry is missing its pre-dotenv…

Error message

active plugin registry is missing its pre-dotenv environment snapshot

What it means

When merging plugin-provided MCP servers into the config, the code needs the plugin registry's captured pre-dotenv environment snapshot (the host environment as it was before .env loading). If the active registry has none, merging cannot proceed safely and fails with this error instead of silently using a wrong environment.

Solutions

  1. Ensure the plugin registry is constructed via the standard path that captures host_environment() before dotenv loading
  2. Fix initialization order: capture the environment snapshot before any .env file is applied
  3. If constructing a registry manually, supply the host environment snapshot explicitly
Defensive patterns

Strategy: validation

Validate before calling

// ensure the registry captured its environment snapshot before merging
anyhow::ensure!(
    registry.host_environment().is_some(),
    "plugin registry built without pre-dotenv env snapshot"
);

Try / catch

match merge_plugin_mcp_servers(config) {
    Err(e) if e.to_string().contains("pre-dotenv environment snapshot") => rebuild_registry_with_env_snapshot_then_retry(),
    other => other,
}

Prevention

When it happens

Trigger: Calling the plugin MCP merge path when registry.host_environment() returns None — i.e. the registry was constructed without capturing the environment snapshot before dotenv was applied.

Common situations: Plugin registry initialized by an alternate entry point that skipped the snapshot; a refactor changed registry construction order so the env capture no longer happens before dotenv loads.

Understand the failure class

Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.

Related errors


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

Appendix: source

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

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 73e0f67d83)