{"record":{"id":"b5c72516210e796e","repo":"alibaba/arthas","slug":"resource-with-uri-already-exists","errorCode":null,"errorMessage":"Resource with URI '{}' already exists","messagePattern":"Resource with URI '(.+?)' already exists","errorType":"validation","errorClass":"McpError","httpStatus":null,"severity":"error","filePath":"arthas-mcp-server/src/main/java/com/taobao/arthas/mcp/server/protocol/server/McpStatelessNettyServer.java","lineNumber":292,"sourceCode":"\t// ---------------------------------------\n\n\tpublic CompletableFuture<Void> addResource(McpStatelessServerFeatures.ResourceSpecification resourceSpecification) {\n\t\tif (resourceSpecification == null || resourceSpecification.getResource() == null) {\n\t\t\tCompletableFuture<Void> future = new CompletableFuture<>();\n\t\t\tfuture.completeExceptionally(new McpError(\"Resource must not be null\"));\n\t\t\treturn future;\n\t\t}\n\t\tif (this.serverCapabilities.getResources() == null) {\n\t\t\tCompletableFuture<Void> future = new CompletableFuture<>();\n\t\t\tfuture.completeExceptionally(new McpError(\"Server must be configured with resource capabilities\"));\n\t\t\treturn future;\n\t\t}\n\n\t\treturn CompletableFuture\n\t\t\t\t.runAsync(() -> {\n\t\t\t\t\tString uri = resourceSpecification.getResource().getUri();\n\t\t\t\t\tif (this.resources.putIfAbsent(uri, resourceSpecification) != null) {\n\t\t\t\t\t\tthrow new CompletionException(new McpError(\"Resource with URI '\" + uri + \"' already exists\"));\n\t\t\t\t\t}\n\t\t\t\t\tlogger.debug(\"Added resource handler: {}\", uri);\n\t\t\t\t})\n\t\t\t\t.exceptionally(ex -> {\n\t\t\t\t\tThrowable cause = ex instanceof CompletionException ? ex.getCause() : ex;\n\t\t\t\t\tlogger.error(\"Error while adding resource '{}'\",\n\t\t\t\t\t\t\tresourceSpecification.getResource().getUri(), cause);\n\t\t\t\t\tthrow new CompletionException(cause);\n\t\t\t\t});\n\t}\n\n\tpublic CompletableFuture<Void> removeResource(String resourceUri) {\n\t\tif (resourceUri == null) {\n\t\t\tCompletableFuture<Void> future = new CompletableFuture<>();\n\t\t\tfuture.completeExceptionally(new McpError(\"Resource URI must not be null\"));\n\t\t\treturn future;\n\t\t}\n\t\tif (this.serverCapabilities.getResources() == null) {","sourceCodeStart":274,"sourceCodeEnd":310,"githubUrl":"https://github.com/alibaba/arthas/blob/21cf2e9ba52b305290be7223b980ff504bb9cb5b/arthas-mcp-server/src/main/java/com/taobao/arthas/mcp/server/protocol/server/McpStatelessNettyServer.java#L274-L310","documentation":"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.","triggerScenarios":"Calling addResource(spec) at runtime when resourceSpecification.getResource().getUri() collides with an existing resource; re-adding after a prior add succeeded.","commonSituations":"Hot re-registration of resources; two plugins registering the same URI (e.g. 'config://app'); retry logic that double-adds.","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."],"exampleFix":"// before\nstatelessServer.addResource(spec).join(); // uri exists\n\n// after\nString uri = spec.getResource().getUri();\nstatelessServer.removeResource(uri).exceptionally(ex -> null).join();\nstatelessServer.addResource(spec).join();","handlingStrategy":"validation","validationCode":"String uri = spec.getResource().getUri();\nstatelessServer.removeResource(uri).exceptionally(ex -> null).join();\nstatelessServer.addResource(spec).join();","typeGuard":null,"tryCatchPattern":"try {\n    statelessServer.addResource(spec).join();\n} catch (CompletionException e) {\n    Throwable c = e.getCause();\n    if (c instanceof McpError me && me.getMessage().contains(\"already exists\")) {\n        statelessServer.removeResource(spec.getResource().getUri())\n            .exceptionally(x -> null).join();\n        statelessServer.addResource(spec).join();\n    } else throw e;\n}","preventionTips":["Use unique URIs for dynamic resources.","Upsert by removing then adding.","Centralize resource registration."],"tags":["mcp","resource","dynamic-registration","duplicate","stateless-server","java"],"backgroundTag":null,"analyzedSha":"21cf2e9ba52b305290be7223b980ff504bb9cb5b","analyzedAt":"2026-08-14T00:57:07.243Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}