alibaba/arthas · error · McpError

Resource with URI '{}' not found

Error message

Resource with URI '{}' not found

What it means

Thrown by McpStatelessNettyServer.removeResource() when dynamically unregistering a resource URI not present in the stateless server's resources map. The async removal returns null from map.remove and 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:320

	}

	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) {
			CompletableFuture<Void> future = new CompletableFuture<>();
			future.completeExceptionally(new McpError("Server must be configured with resource capabilities"));
			return future;
		}

		return CompletableFuture
				.runAsync(() -> {
					McpStatelessServerFeatures.ResourceSpecification removed = this.resources.remove(resourceUri);
					if (removed == null) {
						throw new CompletionException(new McpError("Resource with URI '" + resourceUri + "' not found"));
					}
					logger.debug("Removed resource handler: {}", resourceUri);
				})
				.exceptionally(ex -> {
					Throwable cause = (ex instanceof CompletionException) ? ex.getCause() : ex;
					logger.error("Error while removing resource '{}'", resourceUri, cause);
					throw new CompletionException(cause);
				});
	}

	private McpStatelessRequestHandler<McpSchema.ListResourcesResult> resourcesListRequestHandler() {
		return (exchange, commandContext,  params) -> {
			List<McpSchema.Resource> resourceList = new ArrayList<>();
			for (McpStatelessServerFeatures.ResourceSpecification spec : this.resources.values()) {
				resourceList.add(spec.getResource());
			}
			return CompletableFuture.completedFuture(new McpSchema.ListResourcesResult(resourceList, null));
		};

View on GitHub (pinned to 21cf2e9ba5)

Solutions

  1. Maintain your own registry of added URIs and only remove those present.
  2. Make removal idempotent with exceptionally(ex -> null).
  3. Reuse the exact URI from registration without normalization.
  4. Confirm the same McpStatelessNettyServer instance owns the resource.

Example fix

// before
statelessServer.removeResource(uri).join(); // throws if absent

// after
statelessServer.removeResource(uri)
    .exceptionally(ex -> null)
    .join(); // idempotent
Defensive patterns

Strategy: validation

Validate before calling

Set<String> addedUris = ConcurrentHashMap.newKeySet();
// on add: addedUris.add(uri);
if (addedUris.remove(resourceUri)) {
    statelessServer.removeResource(resourceUri).join();
}

Try / catch

statelessServer.removeResource(resourceUri)
    .exceptionally(ex -> {
        Throwable c = ex instanceof CompletionException ? ex.getCause() : ex;
        if (c instanceof McpError me && me.getMessage().contains("not found")) return null;
        throw new CompletionException(c);
    })
    .join();

Prevention

When it happens

Trigger: Calling removeResource(uri) for a URI never added, already removed, or not byte-identical to the registered key on a stateless server.

Common situations: Idempotent teardown that runs twice; cleanup of a resource that was never registered; URI normalization differences; operating on the wrong server instance.

Related errors


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