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

ThinkingLevel.%s is not supported for model '%s'. This model

Error message

ThinkingLevel.%s is not supported for model '%s'. This model does not support thinkingLevel; use thinkingBudget instead.

What it means

When validating ThinkingLevel options against the target model, a model whose supported-level set is empty (i.e. it does not support thinkingLevel at all) triggers this IllegalArgumentException telling you to use thinkingBudget instead.

Source

Thrown at models/spring-ai-google-genai/src/main/java/org/springframework/ai/google/genai/GoogleGenAiChatModel.java:926

	 * @param level the thinking level to validate
	 * @param modelName the model name
	 * @throws IllegalArgumentException if the level is not supported for the model
	 */
	private static void validateThinkingLevelForModel(GoogleGenAiThinkingLevel level, String modelName) {
		if (level == null || level == GoogleGenAiThinkingLevel.THINKING_LEVEL_UNSPECIFIED || modelName == null) {
			return;
		}
		// Vertex AI style full resource names (e.g.
		// "projects/{project}/locations/{location}/publishers/google/models/{model}")
		// carry the model id as the last path segment.
		String modelId = modelName.substring(modelName.lastIndexOf('/') + 1).toLowerCase(Locale.ROOT);
		Set<GoogleGenAiThinkingLevel> supportedLevels = THINKING_LEVEL_SUPPORT_BY_MODEL.get(modelId);
		if (supportedLevels == null) {
			return;
		}
		if (!supportedLevels.contains(level)) {
			if (supportedLevels.isEmpty()) {
				throw new IllegalArgumentException(String.format(
						"ThinkingLevel.%s is not supported for model '%s'. This model does not support thinkingLevel; use thinkingBudget instead.",
						level, modelName));
			}
			throw new IllegalArgumentException(
					String.format("ThinkingLevel.%s is not supported for model '%s'. Supported levels: %s.", level,
							modelName, supportedLevels.stream().map(Enum::name).collect(Collectors.joining(", "))));
		}
	}

	private List<Content> toGeminiContent(List<Message> instructions) {

		List<Content> contents = instructions.stream()
			.map(message -> Content.builder()
				.role(toGeminiMessageType(message.getMessageType()).getValue())
				.parts(messageToGeminiParts(message))
				.build())
			.toList();

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Remove the thinkingLevel option for this model.
  2. Set thinkingBudget instead (e.g. an Integer budget in the options) for models without thinkingLevel support.
  3. Check the model ID in your options — pick a model that supports thinkingLevel (newer Gemini 2.5+ models) if you need levels.
  4. Wrap options building per-model so thinking options are only applied to capable models.

Example fix

// before
GoogleGenAiChatOptions.builder().model("gemini-2.0-flash")
    .thinkingLevel(GoogleGenAiThinkingLevel.THINKING_LEVEL_HIGH).build();
// after
GoogleGenAiChatOptions.builder().model("gemini-2.0-flash")
    .thinkingBudget(1024).build();
Defensive patterns

Strategy: validation

Validate before calling

if ("gemini-2.0-flash".equals(options.getModel()) && options.getThinkingLevel() != null) {
    throw new IllegalStateException("model does not support thinkingLevel; use thinkingBudget");
}

Try / catch

try { model.call(prompt); } catch (IllegalArgumentException e) { if (e.getMessage().contains("use thinkingBudget instead")) rebuildOptionsWithBudget(); else throw e; }

Prevention

When it happens

Trigger: Setting thinkingLevel (e.g. via GoogleGenAiChatOptions) on a model that appears in THINKING_LEVEL_SUPPORT_BY_MODEL with an empty supported set — typically older Gemini models like gemini-2.0-flash or 1.5 variants that only accept thinkingBudget.

Common situations: Reusing chat options across model IDs; upgrading model names without revisiting thinking configuration; defaults that carry thinkingLevel into requests for non-thinking-capable models.

Related errors


AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11). Data as JSON: /api/errors/3f98da3d9612d729. Report an issue: GitHub.