spring-projects/spring-ai · error · IllegalArgumentException

think level must be one of

Error message

think level must be one of 

What it means

The ThinkLevel compact record constructor validates its level string against VALID_LEVELS = ["low", "medium", "high"] (case-sensitive). Any other non-null string — including different casing or empty strings — triggers this IllegalArgumentException, because only GPT-OSS-style levels are valid ThinkLevel values.

Source

Thrown at models/spring-ai-ollama/src/main/java/org/springframework/ai/ollama/api/ThinkOption.java:152

		public static final ThinkLevel LOW = new ThinkLevel("low");

		/**
		 * Medium thinking level for GPT-OSS.
		 */
		public static final ThinkLevel MEDIUM = new ThinkLevel("medium");

		/**
		 * High thinking level for GPT-OSS.
		 */
		public static final ThinkLevel HIGH = new ThinkLevel("high");

		/**
		 * models/spring-ai-ollama/src/main/java/org/springframework/ai/ollama/api/ThinkOption.java
		 * Creates a new ThinkLevel with validation.
		 */
		public ThinkLevel {
			if (level != null && !VALID_LEVELS.contains(level)) {
				throw new IllegalArgumentException("think level must be one of " + VALID_LEVELS + ", got: " + level);
			}
		}

		@Override
		public Object toJsonValue() {
			return this.level;
		}

	}

}

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Use the provided constants ThinkLevel.LOW, ThinkLevel.MEDIUM, or ThinkLevel.HIGH instead of raw strings.
  2. If the value is dynamic, call level.trim().toLowerCase(Locale.ROOT) and validate membership in {low, medium, high} before constructing ThinkLevel.
  3. For enable/disable semantics on Qwen 3/DeepSeek models, use ThinkBoolean.ENABLED/DISABLED instead of ThinkLevel.
  4. Reject or default invalid config values at application startup with an explicit error message.

Example fix

// before
ThinkOption think = new ThinkLevel(config.getThinkLevel()); // "High"
// after
String lvl = config.getThinkLevel() == null ? null : config.getThinkLevel().trim().toLowerCase(Locale.ROOT);
ThinkOption think = "high".equals(lvl) ? ThinkLevel.HIGH : "medium".equals(lvl) ? ThinkLevel.MEDIUM : "low".equals(lvl) ? ThinkLevel.LOW : null;
Defensive patterns

Strategy: validation

Validate before calling

void validateThinkLevel(String level) {
    if (level != null && !List.of("low", "medium", "high").contains(level.trim().toLowerCase(Locale.ROOT))) {
        throw new IllegalArgumentException("think level must be low, medium or high, got: " + level);
    }
}

Type guard

boolean isValidThinkLevel(String s) {
    return s != null && (s.equals("low") || s.equals("medium") || s.equals("high"));
}

Try / catch

try {
    ThinkLevel level = new ThinkLevel(userValue);
} catch (IllegalArgumentException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("think level must be one of")) {
        level = ThinkLevel.MEDIUM; // documented default
    } else throw e;
}

Prevention

When it happens

Trigger: Calling new ThinkLevel("Low"), ThinkLevel(""), ThinkLevel("minimal"), or any string outside {low, medium, high}; also triggered indirectly by the ThinkOption deserializer when a JSON string think value is not one of the three valid levels.

Common situations: Passing a user-supplied or config-driven think level without normalizing case ("High"); porting code that used other level vocabularies (e.g. "none", "auto", "extreme"); typo like "hig" or "meduim"; binding external JSON with an unexpected level string.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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