Hmbown/CodeWhale · error

MCP import failed

Error message

MCP import failed

What it means

Fallback error for the MCP import-approve/decline flow: the import task's JoinHandle resolves Err (the spawned task panicked or was cancelled) so no inner result exists. `Ok(Err(err))` cases propagate the real error; only the join failure (`Err(_)`) is replaced by this fixed message. This indicates the import never completed rather than that it failed validation.

Solutions

  1. Retry the import approve action — the task loss is usually a transient cancellation race.
  2. Inspect logs for a panic in the MCP import task and fix the underlying cause (e.g. corrupt target config file).
  3. Verify the target MCP config file is writable and not locked by another process before approving.
  4. If it recurs during shutdown, complete imports before exiting the TUI.

Example fix

// before
Err(_) => Err(anyhow::anyhow!("MCP import failed")),
// after: surface the join error for diagnosis
Err(err) => Err(anyhow::anyhow!("MCP import failed: task lost: {err}")),
Defensive patterns

Strategy: try-catch

Try / catch

match import_task.await {
    Ok(Ok(msg)) => apply_import(msg),
    Ok(Err(e)) => show_error(format!("import failed: {e:#}")),
    Err(join_err) => {
        show_error(format!("import task lost: {join_err} — retry the approve action"));
    }
}

Prevention

When it happens

Trigger: Approving or declining an MCP import where the spawned import task panics or is dropped before returning its Result, so `.await` on the handle yields Err and the code maps it to "MCP import failed".

Common situations: Config write panics (e.g. serialization bug) mid-import; TUI shutting down and cancelling the import task; runtime teardown racing with the user clicking Approve.

Related errors


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

Appendix: source

Thrown at crates/tui/src/tui/ui/handlers.rs:830

            let path = path.clone();
            let workspace = app.workspace.clone();
            let plugins = app.plugin_registry.clone();
            #[cfg(test)]
            let ticket = crate::test_support::env_scope_ticket();
            match tokio::task::spawn_blocking(move || {
                #[cfg(test)]
                let _membership = crate::test_support::join_env_scope(ticket);
                mcp_import_apply(&workspace, &path, plugins.as_ref(), &name, approve)
            })
            .await
            {
                Ok(Ok(msg)) => {
                    changed = approve;
                    message = Some(msg);
                    Ok(())
                }
                Ok(Err(err)) => Err(err),
                Err(_) => Err(anyhow::anyhow!("MCP import failed")),
            }
        }
        crate::tui::app::McpUiAction::Validate | crate::tui::app::McpUiAction::Reload => Ok(()),
        crate::tui::app::McpUiAction::Retry { .. } => Ok(()),
    };

    if let Err(err) = action_result {
        add_mcp_message(app, format!("MCP action failed: {err}"));
        return;
    }

    if changed {
        app.mcp_reload_required = true;
    }
    if let Some(message) = message {
        add_mcp_message(app, message);
    }

View on GitHub (pinned to 73e0f67d83)