{"record":{"id":"077fdcb347ca0778","repo":"spring-projects/spring-ai","slug":"clients-must-not-be-empty-077fdc","errorCode":null,"errorMessage":"clients must not be empty","messagePattern":"clients must not be empty","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/sampling/AsyncSamplingSpecification.java","lineNumber":33,"sourceCode":" */\n\npackage org.springframework.ai.mcp.annotation.method.sampling;\n\nimport java.util.Arrays;\nimport java.util.Objects;\nimport java.util.function.Function;\n\nimport io.modelcontextprotocol.spec.McpSchema.CreateMessageRequest;\nimport io.modelcontextprotocol.spec.McpSchema.CreateMessageResult;\nimport reactor.core.publisher.Mono;\n\npublic record AsyncSamplingSpecification(String[] clients,\n\t\tFunction<CreateMessageRequest, Mono<CreateMessageResult>> samplingHandler) {\n\n\tpublic AsyncSamplingSpecification {\n\t\tObjects.requireNonNull(clients, \"clients must not be null\");\n\t\tif (clients.length == 0 || Arrays.stream(clients).map(String::trim).anyMatch(String::isEmpty)) {\n\t\t\tthrow new IllegalArgumentException(\"clients must not be empty\");\n\t\t}\n\t\tObjects.requireNonNull(samplingHandler, \"samplingHandler must not be null\");\n\t}\n\n}\n","sourceCodeStart":15,"sourceCodeEnd":39,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/sampling/AsyncSamplingSpecification.java#L15-L39","documentation":"The AsyncSamplingSpecification compact constructor requires a non-null clients array with at least one non-blank entry after trimming; otherwise it throws IllegalArgumentException with 'clients must not be empty'. The clients array identifies which MCP clients this sampling handler applies to, and an empty set would make the specification meaningless.","triggerScenarios":"new AsyncSamplingSpecification(new String[0], handler) or new AsyncSamplingSpecification(new String[]{\" \", \"\"}, handler) — empty array or only whitespace/empty strings.","commonSituations":"Building client filter lists from config properties that defaulted to empty; splitting an empty/blank config string into an array; passing a null-defaulted varargs call site.","solutions":["Pass at least one real client name, e.g. new AsyncSamplingSpecification(new String[]{\"claude-desktop\"}, handler)","Guard the source list for emptiness before constructing the specification","If 'all clients' is intended, use the API's wildcard/omit-clients variant instead of an empty array"],"exampleFix":"// before\nvar spec = new AsyncSamplingSpecification(new String[0], handler);\n// after\nvar spec = new AsyncSamplingSpecification(new String[]{\"client-a\"}, handler);","handlingStrategy":"validation","validationCode":"if (clients == null || clients.length == 0 || Arrays.stream(clients).map(String::trim).anyMatch(String::isEmpty)) {\n    throw new IllegalArgumentException(\"clients must contain at least one non-blank name\");\n}\nvar spec = new AsyncSamplingSpecification(clients, handler);","typeGuard":null,"tryCatchPattern":"try { new AsyncSamplingSpecification(clients, handler); } catch (IllegalArgumentException e) { fallbackToDefaultClients(); }","preventionTips":["Derive client lists from config with a documented non-empty default","Trim and filter blank entries before constructing specifications","Cover specification construction with unit tests for empty config"],"tags":["validation","clients","sampling"],"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-23T08:17:48.524Z"}