{"record":{"id":"0cce34c6762b10bd","repo":"Hmbown/CodeWhale","slug":"server-server-name-is-not-registered","errorCode":null,"errorMessage":"server '{server_name}' is not registered","messagePattern":"server '(.+?)' is not registered","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"warning","filePath":"crates/mcp/src/lib.rs","lineNumber":346,"sourceCode":"            failed,\n            cancelled,\n        }\n    }\n\n    /// Stop a running server by removing its client.\n    pub fn stop_server(&mut self, server_name: &str) -> Result<()> {\n        self.clients\n            .remove(server_name)\n            .with_context(|| format!(\"server '{server_name}' is not running\"))?;\n        Ok(())\n    }\n\n    /// Remove a server entirely (config and client).\n    pub fn unregister_server(&mut self, server_name: &str) -> Result<()> {\n        let had_config = self.configs.remove(server_name).is_some();\n        self.clients.remove(server_name);\n        if !had_config {\n            bail!(\"server '{server_name}' is not registered\");\n        }\n        Ok(())\n    }\n\n    /// List all tools from all running servers, applying tool filters.\n    pub fn list_tools(&self) -> Result<Vec<McpToolDescriptor>> {\n        let mut out = Vec::new();\n        for (server_name, (_, filter)) in &self.configs {\n            let Some(client) = self.clients.get(server_name) else {\n                continue;\n            };\n            let tools = client.list_tools()?;\n            for tool in tools {\n                if !allowed_by_filter(&tool.tool_name, filter) {\n                    continue;\n                }\n                let qualified_name = qualify_tool_name(server_name, &tool.tool_name);\n                out.push(McpToolDescriptor {","sourceCodeStart":328,"sourceCodeEnd":364,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/mcp/src/lib.rs#L328-L364","documentation":"McpRegistry::unregister_server() bails when there is no config entry for the given name — the server was never registered or was already unregistered. Note the asymmetry: stop_server() only removes the live client, so stop-then-unregister is a valid sequence; the error fires only when configs has no entry for the name.","triggerScenarios":"Calling unregister_server(\"foo\") when foo was never registered; calling it twice (double teardown in a shutdown path plus a drop handler); misspelling the server name; unregistering after a register_server call that itself failed earlier in the same setup routine.","commonSituations":"Error-handling paths that clean up partially-failed registrations; idempotent shutdown code that assumes unregister is a no-op for unknown names; names copied from config that drifted from the registered key.","solutions":["Confirm the exact registered name (the key used in the successful register_server call) before unregistering","Make teardown idempotent by treating this specific bail as success when the goal is 'make sure it is gone'","In setup code, only unregister servers you actually registered — track which registrations succeeded"],"exampleFix":"// before\nregistry.unregister_server(&server_name)?;\n\n// after: idempotent teardown\nif registry.unregister_server(&server_name).is_err() {\n    tracing::debug!(\"server '{server_name}' was not registered; nothing to remove\");\n}","handlingStrategy":"validation","validationCode":"// Only unregister names you successfully registered:\nlet mut registered: Vec<String> = Vec::new();\nif registry.register_server(config.clone(), filter, client).is_ok() {\n    registered.push(config.name.clone());\n}\n// at teardown:\nfor name in registered { let _ = registry.unregister_server(&name); }","typeGuard":null,"tryCatchPattern":"match registry.unregister_server(&server_name) {\n    Ok(()) => Ok(()),\n    Err(err) if err.to_string().ends_with(\"is not registered\") => Ok(()), // idempotent teardown\n    Err(err) => Err(err),\n}","preventionTips":["Track successful registrations and tear down only those","Copy server names from the same constant used at registration, never re-type them","Treat 'not registered' as success in cleanup paths"],"tags":["mcp","registry","lifecycle","idempotency"],"backgroundTag":"unregistered-resource","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}