{"record":{"id":"a6d1482bff961400","repo":"spring-projects/spring-ai","slug":"at-least-one-client-id-must-be-specified","errorCode":null,"errorMessage":"At least one client Id must be specified","messagePattern":"At least one client Id must be specified","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/changed/prompt/AsyncPromptListChangedSpecification.java","lineNumber":32,"sourceCode":" * limitations under the License.\n */\n\npackage org.springframework.ai.mcp.annotation.method.changed.prompt;\n\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.function.Function;\n\nimport io.modelcontextprotocol.spec.McpSchema;\nimport reactor.core.publisher.Mono;\n\npublic record AsyncPromptListChangedSpecification(String[] clients,\n\t\tFunction<List<McpSchema.Prompt>, Mono<Void>> promptListChangeHandler) {\n\n\tpublic AsyncPromptListChangedSpecification {\n\t\tObjects.requireNonNull(clients, \"clients must not be null\");\n\t\tif (clients.length == 0) {\n\t\t\tthrow new IllegalArgumentException(\"At least one client Id must be specified\");\n\t\t}\n\t\tObjects.requireNonNull(promptListChangeHandler, \"promptListChangeHandler must not be null\");\n\t}\n\n}\n","sourceCodeStart":14,"sourceCodeEnd":38,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/changed/prompt/AsyncPromptListChangedSpecification.java#L14-L38","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pass at least one client Id, e.g. new AsyncPromptListChangedSpecification(new String[]{\"client1\"}, handler).","If client Ids come from configuration, validate the property is non-empty before constructing the specification and fail with a clear config error.","Verify the configured Ids match the actual McpSyncClient/McpAsyncClient connection names."],"exampleFix":"// before\nString[] clients = config.getClientIds(); // may be empty\nnew AsyncPromptListChangedSpecification(clients, this::handleChanged);\n// after\nif (clients == null || clients.length == 0) {\n    throw new IllegalStateException(\"mcp.client-ids must contain at least one client Id\");\n}\nnew AsyncPromptListChangedSpecification(clients, this::handleChanged);","handlingStrategy":"validation","validationCode":"if (clients == null || clients.length == 0) {\n    throw new IllegalStateException(\"At least one MCP client Id must be configured for AsyncPromptListChangedSpecification\");\n}\nnew AsyncPromptListChangedSpecification(clients, handler);","typeGuard":null,"tryCatchPattern":"try {\n    new AsyncPromptListChangedSpecification(clients, handler);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"At least one client Id\")) {\n        throw new ConfigurationException(\"mcp client-ids property is empty — set at least one client Id\", e);\n    }\n    throw e;\n}","preventionTips":["Validate the client Ids config property at startup.","Never pass raw dynamic collections without an emptiness check.","Keep client Ids in sync with registered McpAsyncClient bean names."],"tags":["mcp","record-validation","empty-array","configuration"],"backgroundTag":"empty-required-field","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}