spring-projects/spring-ai · error · java.lang.IllegalArgumentException

model cannot be null or empty

Error message

model cannot be null or empty

What it means

buildEmbeddingRequest() merges model-level GoogleGenAiTextEmbeddingOptions with per-request options and validates the result before creating the EmbeddingRequest. If the merged options still have no model name (null or empty), the request cannot name a Gemini embedding model, so this IllegalArgumentException is thrown. The library does not silently fall back to a default in this path.

Source

Thrown at models/spring-ai-google-genai-embedding/src/main/java/org/springframework/ai/google/genai/text/GoogleGenAiTextEmbeddingModel.java:259

						ModelOptionsUtils.mergeOption(requestOptions.getDimensions(), this.options.getDimensions()));

			if (requestOptions instanceof GoogleGenAiTextEmbeddingOptions googleOptions) {
				builder.taskType(ModelOptionsUtils.mergeOption(googleOptions.getTaskType(), this.options.getTaskType()))
					.title(ModelOptionsUtils.mergeOption(googleOptions.getTitle(), this.options.getTitle()))
					.autoTruncate(ModelOptionsUtils.mergeOption(googleOptions.getAutoTruncate(),
							this.options.getAutoTruncate()));
			}
			else {
				builder.taskType(this.options.getTaskType())
					.title(this.options.getTitle())
					.autoTruncate(this.options.getAutoTruncate());
			}
			mergedOptions = builder.build();
		}

		// Validate request options
		if (!StringUtils.hasText(mergedOptions.getModel())) {
			throw new IllegalArgumentException("model cannot be null or empty");
		}

		return new EmbeddingRequest(embeddingRequest.getInstructions(), mergedOptions);
	}

	private EmbeddingResponseMetadata generateResponseMetadata(String model, Integer totalTokens) {
		EmbeddingResponseMetadata metadata = new EmbeddingResponseMetadata();
		metadata.setModel(model);
		Usage usage = getDefaultUsage(totalTokens);
		metadata.setUsage(usage);
		return metadata;
	}

	private DefaultUsage getDefaultUsage(Integer totalTokens) {
		return new DefaultUsage(0, 0, totalTokens);
	}

	@Override

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Set the model on the model-level options: GoogleGenAiTextEmbeddingOptions.builder().model("gemini-embedding-001").build() when constructing the embedding model.
  2. Set the model on the per-request options: new EmbeddingRequest(texts, GoogleGenAiTextEmbeddingOptions.builder().model("gemini-embedding-001").build()).
  3. Verify the merged options chain (request options override model options) isn't replacing a valid model with null/empty.

Example fix

// before
var model = GoogleGenAiTextEmbeddingModel.builder().genAiClient(client).build();

// after
var model = GoogleGenAiTextEmbeddingModel.builder()
    .genAiClient(client)
    .defaultOptions(GoogleGenAiTextEmbeddingOptions.builder().model("gemini-embedding-001").build())
    .build();
Defensive patterns

Strategy: validation

Validate before calling

if (!StringUtils.hasText(options.getModel())) {
    throw new IllegalStateException("Configure GoogleGenAiTextEmbeddingOptions.model before calling the embedding model");
}

Prevention

When it happens

Trigger: Calling embeddingRequest(...) when neither the model default options nor the request EmbeddingOptions specify a model, or when the request options explicitly set model to ""/null overriding a valid model default.

Common situations: Constructing GoogleGenAiTextEmbeddingModel without setting options.model (e.g. builder with only an API key); passing per-request options that zero out the model; refactors renaming the model field so it is no longer populated; copying options objects and dropping the model field.

Understand the failure class

Background: "Must pass :limit option" / "Missing required option" — required option errors explained — 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/74b0a9f4de6e6eb1. Report an issue: GitHub.