{"record":{"id":"5aed354c530425e8","repo":"Hmbown/CodeWhale","slug":"mcp-operation-on-plugin-server-was-cancelled","errorCode":null,"errorMessage":"MCP operation on plugin server '{}' was cancelled after authority changed: {reason}","messagePattern":"MCP operation on plugin server '(.+?)' was cancelled after authority changed: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/mcp.rs","lineNumber":2265,"sourceCode":"    }\n\n    fn catalog_authorized(&self) -> bool {\n        self.config\n            .reviewed_plugin\n            .as_ref()\n            .is_none_or(ReviewedPluginMcpSource::catalog_is_current)\n    }\n\n    async fn finish_guarded_error<T>(&mut self, error: anyhow::Error) -> Result<T> {\n        let reason = self\n            .authority_revocation_reason\n            .lock()\n            .ok()\n            .and_then(|reason| reason.clone());\n        if let Some(reason) = reason {\n            self.transport.shutdown().await;\n            self.state = ConnectionState::Disconnected;\n            anyhow::bail!(\n                \"MCP operation on plugin server '{}' was cancelled after authority changed: {reason}\",\n                self.name\n            );\n        }\n        Err(error)\n    }\n}\n\n/// Apply the ambient proxy policy for MCP HTTP transports.\n///\n/// User-authored MCP configuration keeps the long-standing corporate-proxy\n/// behavior. Reviewed plugin bundles deliberately do not: proxy URLs can carry\n/// credentials and proxy processes can observe request metadata, neither of\n/// which is part of the v1 reviewed remote authority. Return before consulting\n/// the environment so even reading ambient proxy credentials is impossible on\n/// that path, and call `no_proxy` explicitly to keep this invariant stable if\n/// reqwest's defaults change.\nfn configure_mcp_proxy<F>(","sourceCodeStart":2247,"sourceCodeEnd":2283,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/tui/src/mcp.rs#L2247-L2283","documentation":"finish_guarded_error wraps every error coming out of a connection operation and checks the shared authority_revocation_reason lock. If a reviewed plugin bundle's authority (catalog hash/source) was revoked or changed while an operation was in flight, the transport is shut down, the state set to Disconnected, and this error replaces the original one. It is a security guard: stale plugin connections must not keep operating under an authority that no longer approves them.","triggerScenarios":"A tool call is in flight on a reviewed-plugin MCP server when the plugin catalog is updated or the plugin's review state is revoked — validate_before_use in get_or_connect will then refuse future use, and finish_guarded_error converts already-started operations into this cancellation error.","commonSituations":"Plugin bundle upgraded while the session held open connections; a security review revoked the plugin between turns; CI environments that mutate the plugin registry concurrently with tool execution.","solutions":["Update or re-approve the reviewed plugin bundle so its catalog is current, then reconnect — get_or_connect revalidates via validate_before_use.","Do not retry blindly: the error means the running code is no longer authorized; surface it to the user or operator.","If the revocation was accidental, restore the exact reviewed plugin files/catalog so the hash matches again.","Check for concurrent processes mutating the plugin registry workspace."],"exampleFix":"// before\nmatch conn.call_tool(name, args, t).await { Err(e) => retry(e) } // loops forever on authority revocation\n\n// after\nmatch conn.call_tool(name, args, t).await {\n    Err(e) if e.to_string().contains(\"authority changed\") => {\n        return Err(e); // terminal: surface to user, re-approve plugin first\n    }\n    other => other,\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Rust: terminal security error — never auto-retry\nmatch result {\n    Err(e) if e.to_string().contains(\"authority changed\") => {\n        tracing::error!(\"plugin authority revoked mid-operation: {e:#}\");\n        return Err(e); // user must re-approve the plugin bundle\n    }\n    other => other,\n}","preventionTips":["Never write retry loops that swallow authority-revocation errors.","Re-approve or update the reviewed plugin bundle before reconnecting.","Expect get_or_connect to refuse the server afterwards via validate_before_use — that is the same guard, do not bypass it."],"tags":["mcp","plugin","security","authority"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}