spring-projects/spring-ai · error · IllegalArgumentException

At least one client Id must be specified

Error message

At least one client Id must be specified

What it means

IllegalArgumentException thrown in the compact constructor of the AsyncPromptListChangedSpecification record when the clients array is non-null but empty. A prompt-list-changed specification must name at least one MCP client (connection) Id to attach the handler to; an empty array is a configuration error since the handler would never be bound to anything.

Source

Thrown at mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/changed/prompt/AsyncPromptListChangedSpecification.java:32

 * limitations under the License.
 */

package org.springframework.ai.mcp.annotation.method.changed.prompt;

import java.util.List;
import java.util.Objects;
import java.util.function.Function;

import io.modelcontextprotocol.spec.McpSchema;
import reactor.core.publisher.Mono;

public record AsyncPromptListChangedSpecification(String[] clients,
		Function<List<McpSchema.Prompt>, Mono<Void>> promptListChangeHandler) {

	public AsyncPromptListChangedSpecification {
		Objects.requireNonNull(clients, "clients must not be null");
		if (clients.length == 0) {
			throw new IllegalArgumentException("At least one client Id must be specified");
		}
		Objects.requireNonNull(promptListChangeHandler, "promptListChangeHandler must not be null");
	}

}

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Pass at least one client Id, e.g. new AsyncPromptListChangedSpecification(new String[]{"client1"}, handler).
  2. If client Ids come from configuration, validate the property is non-empty before constructing the specification and fail with a clear config error.
  3. Verify the configured Ids match the actual McpSyncClient/McpAsyncClient connection names.

Example fix

// before
String[] clients = config.getClientIds(); // may be empty
new AsyncPromptListChangedSpecification(clients, this::handleChanged);
// after
if (clients == null || clients.length == 0) {
    throw new IllegalStateException("mcp.client-ids must contain at least one client Id");
}
new AsyncPromptListChangedSpecification(clients, this::handleChanged);
Defensive patterns

Strategy: validation

Validate before calling

if (clients == null || clients.length == 0) {
    throw new IllegalStateException("At least one MCP client Id must be configured for AsyncPromptListChangedSpecification");
}
new AsyncPromptListChangedSpecification(clients, handler);

Try / catch

try {
    new AsyncPromptListChangedSpecification(clients, handler);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("At least one client Id")) {
        throw new ConfigurationException("mcp client-ids property is empty — set at least one client Id", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Constructing new AsyncPromptListChangedSpecification(new String[0], handler) or new AsyncPromptListChangedSpecification(new String[]{}, handler). Also happens when the client Id list is built dynamically (e.g. from config or a collection) and happens to be empty.

Common situations: Client Ids loaded from an empty config property or environment; filtering a client list down to zero entries; copy-pasted specification setup where the clients literal was never filled in; changing McpSyncClient bean names so the lookup list is empty.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11). Data as JSON: /api/errors/a6d1482bff961400. Report an issue: GitHub.