alibaba/arthas · error · McpError
Prompt with name '{}' already exists
Error message
Prompt with name '{}' already exists What it means
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.
Source
Thrown at arthas-mcp-server/src/main/java/com/taobao/arthas/mcp/server/protocol/server/McpStatelessNettyServer.java:384
public CompletableFuture<Void> addPrompt(McpStatelessServerFeatures.PromptSpecification promptSpecification) {
if (promptSpecification == null) {
CompletableFuture<Void> future = new CompletableFuture<>();
future.completeExceptionally(new McpError("Prompt specification must not be null"));
return future;
}
if (this.serverCapabilities.getPrompts() == null) {
CompletableFuture<Void> future = new CompletableFuture<>();
future.completeExceptionally(new McpError("Server must be configured with prompt capabilities"));
return future;
}
return CompletableFuture
.runAsync(() -> {
String name = promptSpecification.getPrompt().getName();
McpStatelessServerFeatures.PromptSpecification existing =
this.prompts.putIfAbsent(name, promptSpecification);
if (existing != null) {
throw new CompletionException(new McpError("Prompt with name '" + name + "' already exists"));
}
logger.debug("Added prompt handler: {}", name);
})
.exceptionally(ex -> {
Throwable cause = (ex instanceof CompletionException) ? ex.getCause() : ex;
String name = promptSpecification.getPrompt().getName();
logger.error("Error while adding prompt '{}'", name, cause);
throw new CompletionException(cause);
});
}
public CompletableFuture<Void> removePrompt(String promptName) {
if (promptName == null || promptName.isEmpty()) {
CompletableFuture<Void> future = new CompletableFuture<>();
future.completeExceptionally(new McpError("Prompt name must not be null or empty"));
return future;
}
if (this.serverCapabilities.getPrompts() == null) {View on GitHub (pinned to 21cf2e9ba5)
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.
Example fix
// before statelessServer.addPrompt(spec).join(); // name exists // after String name = spec.getPrompt().getName(); statelessServer.removePrompt(name).exceptionally(ex -> null).join(); statelessServer.addPrompt(spec).join();
Defensive patterns
Strategy: validation
Validate before calling
String name = spec.getPrompt().getName(); statelessServer.removePrompt(name).exceptionally(ex -> null).join(); statelessServer.addPrompt(spec).join();
Try / catch
try {
statelessServer.addPrompt(spec).join();
} catch (CompletionException e) {
Throwable c = e.getCause();
if (c instanceof McpError me && me.getMessage().contains("already exists")) {
statelessServer.removePrompt(spec.getPrompt().getName())
.exceptionally(x -> null).join();
statelessServer.addPrompt(spec).join();
} else throw e;
} Prevention
- Namespace prompt names.
- Upsert: remove (ignore absent) then add.
- Avoid concurrent duplicate adds.
When it happens
Trigger: Calling addPrompt(spec) at runtime when getPrompt().getName() collides with an existing prompt; re-adding after a successful add.
Common situations: Live prompt re-registration; plugin load colliding with an existing prompt name; retry-based double add.
Related errors
- Prompt with name '${promptName}' already exists
- Tool with name '{}' already exists
- Resource with URI '{}' already exists
- Prompt with name '{}' not found
- Prompt with name '${promptName}' not found
AI-assisted analysis of alibaba/arthas@21cf2e9ba5 (2026-08-14).
Data as JSON: /api/errors/8205ac7a967e4d24.
Report an issue: GitHub.