alibaba/arthas · error · McpError
Resource with URI '${resourceUri}' not found
Error message
Resource with URI '${resourceUri}' not found What it means
Thrown by McpNettyServer.removeResource() when you try to dynamically unregister a resource whose URI is not currently registered. The server holds resources in a name-keyed map; a removal that finds no existing entry fails the returned CompletableFuture with this McpError (wrapped in a CompletionException). It is a stateful-server runtime error, distinct from the resource-capabilities-missing guard that runs before it.
Source
Thrown at arthas-mcp-server/src/main/java/com/taobao/arthas/mcp/server/protocol/server/McpNettyServer.java:467
});
}
public CompletableFuture<Void> removeResource(String resourceUri) {
if (resourceUri == null) {
CompletableFuture<Void> future = new CompletableFuture<>();
future.completeExceptionally(new McpError("Resource URI must not be null"));
return future;
}
if (this.serverCapabilities.getResources() == null) {
CompletableFuture<Void> future = new CompletableFuture<>();
future.completeExceptionally(new McpError("Server must be configured with resource capabilities"));
return future;
}
return CompletableFuture.supplyAsync(() -> {
McpServerFeatures.ResourceSpecification removed = this.resources.remove(resourceUri);
if (removed == null) {
throw new CompletionException(new McpError("Resource with URI '" + resourceUri + "' not found"));
}
logger.debug("Removed resource handler: {}", resourceUri);
return null;
}).thenCompose(ignored -> {
if (this.serverCapabilities.getResources().getListChanged()) {
return notifyResourcesListChanged();
}
return CompletableFuture.completedFuture(null);
}).exceptionally(ex -> {
Throwable cause = (ex instanceof CompletionException) ? ex.getCause() : ex;
logger.error("Error while removing resource '{}'", resourceUri, cause);
throw new CompletionException(cause);
});
}
public CompletableFuture<Void> notifyResourcesListChanged() {
return this.mcpTransportProvider.notifyClients(McpSchema.METHOD_NOTIFICATION_RESOURCES_LIST_CHANGED, null);View on GitHub (pinned to 21cf2e9ba5)
Solutions
- Track registered resource URIs in your own set and only call removeResource for URIs you know are present.
- Verify the exact URI string passed to addResource is reused verbatim for removal (no trimming/normalization).
- Catch CompletionException/McpError on the returned future and treat 'not found' as a no-op for idempotent cleanup.
- Confirm you are operating on the same McpNettyServer instance that owns the resource.
Example fix
// before
server.removeResource(uri).join(); // throws if absent
// after
Set<String> registered = ConcurrentHashMap.newKeySet();
server.addResource(spec);
registered.add(uri);
// ...
if (registered.remove(uri)) {
server.removeResource(uri).join();
} Defensive patterns
Strategy: validation
Validate before calling
// Track URIs you registered and guard removal
Set<String> registeredResources = ConcurrentHashMap.newKeySet();
// on add: registeredResources.add(uri);
if (registeredResources.remove(resourceUri)) {
server.removeResource(resourceUri).join();
} Try / catch
// Idempotent removal: swallow 'not found'
server.removeResource(resourceUri)
.exceptionally(ex -> {
if (isMcpError(ex, "not found")) return null;
throw new CompletionException(ex instanceof CompletionException
? ex.getCause() : ex);
})
.join(); Prevention
- Keep your own set of registered URIs and remove only those.
- Reuse the exact URI string from registration for removal.
- Make cleanup code idempotent by treating 'not found' as success.
When it happens
Trigger: Calling removeResource(resourceUri) where resourceUri was never added, was already removed, or has expired. Also when the URI passed does not byte-match the key used at registration (trailing slash, case, scheme).
Common situations: Double removal of the same resource; removal on a server instance that did not register the resource (e.g. wrong server or session); cleanup code running after startup registration changed order; URI normalization mismatch between add and remove.
Related errors
- Prompt with name '${promptName}' already exists
- Prompt with name '${promptName}' not found
- Resource with URI '{}' already exists
- Resource with URI '{}' not found
- Tool with name '{}' already exists
AI-assisted analysis of alibaba/arthas@21cf2e9ba5 (2026-08-14).
Data as JSON: /api/errors/7dd4bbaa8f6beb46.
Report an issue: GitHub.