alibaba/arthas · error · McpError
Prompt with name ' ' already exists
Error message
Prompt with name '${promptName}' already exists What it means
Thrown by McpNettyServer.addPrompt() when a PromptSpecification whose prompt name already exists in the server's prompts map is registered again. Registration uses putIfAbsent, so a second add of the same name fails the returned future with this McpError instead of silently overwriting. Prompt names are the unique key for the MCP prompts capability.
Solutions
- Use unique prompt names per PromptSpecification; namespace them (e.g. 'plugin.promptName').
- Before addPrompt, check the existing set or call removePrompt first if you intend to replace.
- Centralize prompt registration in one place to avoid duplicate adds from different modules.
- Catch the CompletionException/McpError and log/skip on conflict rather than failing the whole startup.
Example fix
// before server.addPrompt(duplicatePromptSpec).join(); // 'review' already exists // after String name = spec.getPrompt().getName(); server.removePrompt(name).exceptionally(ex -> null).join(); // ignore if absent server.addPrompt(spec).join();
Defensive patterns
Strategy: validation
Validate before calling
// Only add a prompt if the name is not already registered
String name = spec.getPrompt().getName();
boolean absent = currentPromptNames.add(name); // shared ConcurrentHashMap.newKeySet()
if (absent) {
server.addPrompt(spec).join();
} Try / catch
try {
server.addPrompt(spec).join();
} catch (CompletionException e) {
if (e.getCause() instanceof McpError me && me.getMessage().contains("already exists")) {
// upsert: remove then re-add
server.removePrompt(spec.getPrompt().getName())
.exceptionally(x -> null).join();
server.addPrompt(spec).join();
} else throw e;
} Prevention
- Namespace prompt names to avoid cross-module collisions.
- Centralize prompt registration in one component.
- For replacement semantics, removePrompt first (ignoring absent).
When it happens
Trigger: Calling addPrompt with a spec whose getPrompt().getName() collides with an already-registered prompt; re-running registration logic on startup without clearing prior state; adding the same prompt from two modules.
Common situations: Hot-reload/restart of registration code while the server object persists; two plugins registering a prompt named the same (e.g. 'review'); copy-paste of a PromptSpecification without renaming.
Related errors
- Prompt with name ' ' already exists
- Prompt with name ' ' not found
- Prompt with name ' ' not found
- Resource with URI ' ' already exists
- Resource with URI ' ' not found
AI-assisted analysis of alibaba/arthas@21cf2e9ba5 (2026-08-14).
Data as JSON: /api/errors/da7e145b121e896f.
Report an issue: GitHub.
Appendix: source
Thrown at arthas-mcp-server/src/main/java/com/taobao/arthas/mcp/server/protocol/server/McpNettyServer.java:539
// ---------------------------------------
public CompletableFuture<Void> addPrompt(McpServerFeatures.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.supplyAsync(() -> {
McpServerFeatures.PromptSpecification existing = this.prompts
.putIfAbsent(promptSpecification.getPrompt().getName(), promptSpecification);
if (existing != null) {
throw new CompletionException(
new McpError(
"Prompt with name '" + promptSpecification.getPrompt().getName() + "' already exists"));
}
logger.debug("Added prompt handler: {}", promptSpecification.getPrompt().getName());
return null;
}).thenCompose(ignored -> {
if (this.serverCapabilities.getPrompts().getListChanged()) {
return notifyPromptsListChanged();
}
return CompletableFuture.completedFuture(null);
}).exceptionally(ex -> {
Throwable cause = (ex instanceof CompletionException) ? ex.getCause() : ex;
logger.error("Error while adding prompt '{}'", promptSpecification.getPrompt().getName(), cause);
throw new CompletionException(cause);
});
}
View on GitHub (pinned to 21cf2e9ba5)