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

  1. Check or removeResource before addResource to implement upsert semantics.
  2. Use unique, namespaced URIs for dynamically added resources.
  3. Catch CompletionException/McpError on the future and skip on duplicate.
  4. 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

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


AI-assisted analysis of alibaba/arthas@21cf2e9ba5 (2026-08-14). Data as JSON: /api/errors/b5c72516210e796e. Report an issue: GitHub.