alibaba/arthas · error · McpError
Resource with URI '{}' already exists
Error message
Resource with URI '{}' already exists What it means
Thrown by McpStatelessNettyServer.addResource() when dynamically registering a resource whose URI already exists in the resources map (putIfAbsent returns non-null). The async add fails the returned CompletableFuture with this McpError wrapped in CompletionException. URIs are the unique key for the resources capability.
Source
Thrown at arthas-mcp-server/src/main/java/com/taobao/arthas/mcp/server/protocol/server/McpStatelessNettyServer.java:292
// ---------------------------------------
public CompletableFuture<Void> addResource(McpStatelessServerFeatures.ResourceSpecification resourceSpecification) {
if (resourceSpecification == null || resourceSpecification.getResource() == null) {
CompletableFuture<Void> future = new CompletableFuture<>();
future.completeExceptionally(new McpError("Resource 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
.runAsync(() -> {
String uri = resourceSpecification.getResource().getUri();
if (this.resources.putIfAbsent(uri, resourceSpecification) != null) {
throw new CompletionException(new McpError("Resource with URI '" + uri + "' already exists"));
}
logger.debug("Added resource handler: {}", uri);
})
.exceptionally(ex -> {
Throwable cause = ex instanceof CompletionException ? ex.getCause() : ex;
logger.error("Error while adding resource '{}'",
resourceSpecification.getResource().getUri(), cause);
throw new CompletionException(cause);
});
}
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) {View on GitHub (pinned to 21cf2e9ba5)
Solutions
- Check or removeResource before addResource to implement upsert semantics.
- Use unique, namespaced URIs for dynamically added resources.
- Catch CompletionException/McpError on the future and skip on duplicate.
- Centralize resource registration to avoid concurrent duplicate adds.
Example fix
// before statelessServer.addResource(spec).join(); // uri exists // after String uri = spec.getResource().getUri(); statelessServer.removeResource(uri).exceptionally(ex -> null).join(); statelessServer.addResource(spec).join();
Defensive patterns
Strategy: validation
Validate before calling
String uri = spec.getResource().getUri(); statelessServer.removeResource(uri).exceptionally(ex -> null).join(); statelessServer.addResource(spec).join();
Try / catch
try {
statelessServer.addResource(spec).join();
} catch (CompletionException e) {
Throwable c = e.getCause();
if (c instanceof McpError me && me.getMessage().contains("already exists")) {
statelessServer.removeResource(spec.getResource().getUri())
.exceptionally(x -> null).join();
statelessServer.addResource(spec).join();
} else throw e;
} Prevention
- Use unique URIs for dynamic resources.
- Upsert by removing then adding.
- Centralize resource registration.
When it happens
Trigger: Calling addResource(spec) at runtime when resourceSpecification.getResource().getUri() collides with an existing resource; re-adding after a prior add succeeded.
Common situations: Hot re-registration of resources; two plugins registering the same URI (e.g. 'config://app'); retry logic that double-adds.
Related errors
- Tool with name '{}' already exists
- Resource with URI '{}' not found
- Prompt with name '{}' already exists
- Resource with URI '${resourceUri}' not found
- Prompt with name '${promptName}' already exists
AI-assisted analysis of alibaba/arthas@21cf2e9ba5 (2026-08-14).
Data as JSON: /api/errors/b5c72516210e796e.
Report an issue: GitHub.