{"record":{"id":"cefbc34919950fbc","repo":"spring-projects/spring-ai","slug":"at-least-one-client-id-must-be-specified-cefbc3","errorCode":null,"errorMessage":"At least one client Id must be specified","messagePattern":"At least one client Id must be specified","errorType":"validation","errorClass":"java.lang.IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/progress/AsyncProgressSpecification.java","lineNumber":37,"sourceCode":"import java.util.Arrays;\nimport java.util.Objects;\nimport java.util.function.Function;\n\nimport io.modelcontextprotocol.spec.McpSchema.ProgressNotification;\nimport reactor.core.publisher.Mono;\n\n/**\n * Specification for asynchronous progress handlers.\n *\n * @param clients The client IDs for the progress handler\n * @param progressHandler The function that handles progress notifications asynchronously\n * @author Christian Tzolov\n */\npublic record AsyncProgressSpecification(String[] clients, Function<ProgressNotification, Mono<Void>> progressHandler) {\n\tpublic AsyncProgressSpecification {\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(\"At least one client Id must be specified\");\n\t\t}\n\t\tObjects.requireNonNull(progressHandler, \"progressHandler must not be null\");\n\t}\n\n}\n","sourceCodeStart":19,"sourceCodeEnd":43,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/progress/AsyncProgressSpecification.java#L19-L43","documentation":"The AsyncProgressSpecification record requires a non-empty clients array with no blank entries, since progress notifications must be addressed to at least one specific client Id. The compact constructor throws IllegalArgumentException when clients is empty, or when any element is null/blank after trimming.","triggerScenarios":"Constructing new AsyncProgressSpecification(new String[0], handler), new AsyncProgressSpecification(new String[]{\"\", \" \"}, handler), or new AsyncProgressSpecification(null, handler) (the latter triggers the null message instead).","commonSituations":"Building client lists dynamically from configuration where the property is missing or empty; forgetting to fill a defaults list; whitespace-only entries from comma-split config strings.","solutions":["Pass at least one valid, non-blank client Id in the clients array.","Filter blank entries from the config-derived list before constructing the specification.","If broadcast to all clients is intended, enumerate the known client Ids explicitly (this API has no wildcard)."],"exampleFix":"// before\nnew AsyncProgressSpecification(new String[]{}, handler);\n// after\nnew AsyncProgressSpecification(new String[]{\"client-1\"}, handler);","handlingStrategy":"validation","validationCode":"String[] clients = configClients == null ? new String[0]\n    : Arrays.stream(configClients).map(String::trim).filter(s -> !s.isEmpty()).toArray(String[]::new);\nif (clients.length == 0) throw new IllegalStateException(\"Configure at least one client Id for progress notifications\");\nvar spec = new AsyncProgressSpecification(clients, handler);","typeGuard":"function validClients(arr) {\n  return Array.isArray(arr) && arr.length > 0 && arr.every(c => typeof c === 'string' && c.trim().length > 0);\n}","tryCatchPattern":"try {\n    return new AsyncProgressSpecification(rawClients, handler);\n} catch (IllegalArgumentException e) {\n    if (\"At least one client Id must be specified\".equals(e.getMessage())) {\n        throw new ConfigurationException(\"clients property is missing or blank — set mcp progress client ids\", e);\n    }\n    throw e;\n}","preventionTips":["Trim and filter whitespace entries when splitting client lists from config strings.","Provide application properties defaults for progress client ids.","Validate configuration at startup before building specifications."],"tags":["mcp","progress-notification","validation","empty-list"],"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"}