{"record":{"id":"8205ac7a967e4d24","repo":"alibaba/arthas","slug":"prompt-with-name-already-exists","errorCode":null,"errorMessage":"Prompt with name '{}' already exists","messagePattern":"Prompt with name '(.+?)' 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":384,"sourceCode":"\tpublic CompletableFuture<Void> addPrompt(McpStatelessServerFeatures.PromptSpecification promptSpecification) {\n\t\tif (promptSpecification == null) {\n\t\t\tCompletableFuture<Void> future = new CompletableFuture<>();\n\t\t\tfuture.completeExceptionally(new McpError(\"Prompt specification must not be null\"));\n\t\t\treturn future;\n\t\t}\n\t\tif (this.serverCapabilities.getPrompts() == null) {\n\t\t\tCompletableFuture<Void> future = new CompletableFuture<>();\n\t\t\tfuture.completeExceptionally(new McpError(\"Server must be configured with prompt 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 name = promptSpecification.getPrompt().getName();\n\t\t\t\t\tMcpStatelessServerFeatures.PromptSpecification existing =\n\t\t\t\t\t\t\tthis.prompts.putIfAbsent(name, promptSpecification);\n\t\t\t\t\tif (existing != null) {\n\t\t\t\t\t\tthrow new CompletionException(new McpError(\"Prompt with name '\" + name + \"' already exists\"));\n\t\t\t\t\t}\n\t\t\t\t\tlogger.debug(\"Added prompt handler: {}\", name);\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\tString name = promptSpecification.getPrompt().getName();\n\t\t\t\t\tlogger.error(\"Error while adding prompt '{}'\", name, cause);\n\t\t\t\t\tthrow new CompletionException(cause);\n\t\t\t\t});\n\t}\n\n\tpublic CompletableFuture<Void> removePrompt(String promptName) {\n\t\tif (promptName == null || promptName.isEmpty()) {\n\t\t\tCompletableFuture<Void> future = new CompletableFuture<>();\n\t\t\tfuture.completeExceptionally(new McpError(\"Prompt name must not be null or empty\"));\n\t\t\treturn future;\n\t\t}\n\t\tif (this.serverCapabilities.getPrompts() == null) {","sourceCodeStart":366,"sourceCodeEnd":402,"githubUrl":"https://github.com/alibaba/arthas/blob/21cf2e9ba52b305290be7223b980ff504bb9cb5b/arthas-mcp-server/src/main/java/com/taobao/arthas/mcp/server/protocol/server/McpStatelessNettyServer.java#L366-L402","documentation":"Thrown by McpStatelessNettyServer.addPrompt() when dynamically registering a PromptSpecification whose prompt name already exists in the stateless server's prompts map (putIfAbsent returns non-null). The async add fails the returned CompletableFuture with this McpError wrapped in CompletionException.","triggerScenarios":"Calling addPrompt(spec) at runtime when getPrompt().getName() collides with an existing prompt; re-adding after a successful add.","commonSituations":"Live prompt re-registration; plugin load colliding with an existing prompt name; retry-based double add.","solutions":["removePrompt first (idempotently) to upsert, or check current prompts before adding.","Use unique namespaced prompt names.","Catch CompletionException/McpError and skip on duplicate.","Coordinate prompt registration to prevent concurrent duplicate adds."],"exampleFix":"// before\nstatelessServer.addPrompt(spec).join(); // name exists\n\n// after\nString name = spec.getPrompt().getName();\nstatelessServer.removePrompt(name).exceptionally(ex -> null).join();\nstatelessServer.addPrompt(spec).join();","handlingStrategy":"validation","validationCode":"String name = spec.getPrompt().getName();\nstatelessServer.removePrompt(name).exceptionally(ex -> null).join();\nstatelessServer.addPrompt(spec).join();","typeGuard":null,"tryCatchPattern":"try {\n    statelessServer.addPrompt(spec).join();\n} catch (CompletionException e) {\n    Throwable c = e.getCause();\n    if (c instanceof McpError me && me.getMessage().contains(\"already exists\")) {\n        statelessServer.removePrompt(spec.getPrompt().getName())\n            .exceptionally(x -> null).join();\n        statelessServer.addPrompt(spec).join();\n    } else throw e;\n}","preventionTips":["Namespace prompt names.","Upsert: remove (ignore absent) then add.","Avoid concurrent duplicate adds."],"tags":["mcp","prompt","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"}