{"record":{"id":"c56db4aa0093e3d4","repo":"spring-projects/spring-ai","slug":"no-embedding-input-is-provided-all-texts-are-nul","errorCode":null,"errorMessage":"No embedding input is provided - all texts are null or empty","messagePattern":"No embedding input is provided - all texts are null or empty","errorType":"exception","errorClass":"java.lang.IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"models/spring-ai-google-genai-embedding/src/main/java/org/springframework/ai/google/genai/text/GoogleGenAiTextEmbeddingModel.java","lineNumber":172,"sourceCode":"\t\t\t\t// Set task type if specified - this might need to be handled differently\n\t\t\t\t// as the new SDK might not have a direct taskType field\n\t\t\t\t// We'll need to check the SDK documentation for this\n\n\t\t\t\tEmbedContentConfig config = configBuilder.build();\n\n\t\t\t\t// Convert instructions to Content list for embedding\n\t\t\t\tList<String> texts = embeddingRequest.getInstructions();\n\n\t\t\t\t// Validate that we have texts to embed\n\t\t\t\tif (texts == null || texts.isEmpty()) {\n\t\t\t\t\tthrow new IllegalArgumentException(\"No embedding input is provided - instructions list is empty\");\n\t\t\t\t}\n\n\t\t\t\t// Filter out null or empty strings\n\t\t\t\tList<String> validTexts = texts.stream().filter(StringUtils::hasText).toList();\n\n\t\t\t\tif (validTexts.isEmpty()) {\n\t\t\t\t\tthrow new IllegalArgumentException(\"No embedding input is provided - all texts are null or empty\");\n\t\t\t\t}\n\n\t\t\t\t// Call the embedding API with retry\n\t\t\t\tEmbedContentResponse embeddingResponse = RetryUtils.execute(this.retryTemplate,\n\t\t\t\t\t\t() -> this.genAiClient.models.embedContent(modelName, validTexts, config));\n\n\t\t\t\t// Process the response\n\t\t\t\t// Note: We need to handle the case where some texts were filtered out\n\t\t\t\t// The response will only contain embeddings for valid texts\n\t\t\t\tint totalTokenCount = 0;\n\t\t\t\tList<Embedding> embeddingList = new ArrayList<>();\n\n\t\t\t\t// Create a map to track original indices\n\t\t\t\tint originalIndex = 0;\n\t\t\t\tint validIndex = 0;\n\n\t\t\t\tif (embeddingResponse.embeddings().isPresent()) {\n\t\t\t\t\tfor (String originalText : texts) {","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/models/spring-ai-google-genai-embedding/src/main/java/org/springframework/ai/google/genai/text/GoogleGenAiTextEmbeddingModel.java#L154-L190","documentation":"GoogleGenAiTextEmbeddingModel.call() filters the input text list for entries with actual content before calling the Gemini embedContent API. If every provided text is null or empty (after filtering with StringUtils.hasText), there is nothing to embed, so the model throws this IllegalArgumentException instead of sending a pointless API request. The Gemini embedding API requires at least one non-empty text per request.","triggerScenarios":"Calling call(new EmbeddingRequest(List.of(\"\"), options)) or call(new EmbeddingRequest(List.of(null, \"\"), options)) — i.e. any EmbeddingRequest whose instructions list contains only null, empty, or whitespace-only strings.","commonSituations":"Upstream data pipelines producing blank documents (failed file reads, empty DB cells); callers building batches where an earlier filter removed all real texts but left the empty/null placeholders; splitting a document on delimiters that yield empty segments; a List with all-null entries after a failed mapping step.","solutions":["Filter the instructions before building the EmbeddingRequest: texts.stream().filter(StringUtils::hasText).toList(), and skip the call if the result is empty.","Fix the upstream data source so it produces non-empty text (check file reads, DB columns, or chunking logic that emits blank segments).","If empty input is legitimate, guard the call site and return an empty EmbeddingResponse instead of invoking the model."],"exampleFix":"// before\nEmbeddingRequest request = new EmbeddingRequest(chunks, options);\nEmbeddingResponse response = embeddingModel.call(request);\n\n// after\nList<String> validChunks = chunks.stream().filter(StringUtils::hasText).toList();\nif (validChunks.isEmpty()) {\n    return new EmbeddingResponse(List.of());\n}\nEmbeddingResponse response = embeddingModel.call(new EmbeddingRequest(validChunks, options));","handlingStrategy":"validation","validationCode":"List<String> validTexts = texts == null ? List.of() : texts.stream().filter(StringUtils::hasText).toList();\nif (validTexts.isEmpty()) { return new EmbeddingResponse(List.of()); }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always filter instructions with StringUtils.hasText before building an EmbeddingRequest.","Validate upstream data pipelines that feed document embeddings for blank segments.","Add unit tests covering null/empty instruction lists."],"tags":["embedding","validation","illegal-argument","empty-input"],"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"}