spring-projects/spring-ai · error · IllegalArgumentException

Only outputType or outputJsonSchema can be set, not both.

Error message

Only outputType or outputJsonSchema can be set, not both.

What it means

StructuredOutputValidationAdvisor.Builder.build() enforces that the output format is specified exactly one way: either outputType (a Java type from which a schema is generated) or outputJsonSchema (an explicit schema string). Setting both is ambiguous and throws IllegalArgumentException('Only outputType or outputJsonSchema can be set, not both.').

Source

Thrown at spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/advisor/StructuredOutputValidationAdvisor.java:341

		 * {@link JacksonUtils#getDefaultJsonMapper()}.
		 * @param jsonMapper the JSON mapper
		 * @return this builder
		 */
		public Builder jsonMapper(JsonMapper jsonMapper) {
			this.jsonMapper = jsonMapper;
			return this;
		}

		/**
		 * Builds the StructuredOutputValidationAdvisor.
		 * @return a new StructuredOutputValidationAdvisor instance
		 * @throws IllegalArgumentException if neither outputType nor outputJsonSchema is
		 * set, or if both are set
		 */
		public StructuredOutputValidationAdvisor build() {

			if (StringUtils.hasText(this.outputJsonSchema) && this.outputType != null) {
				throw new IllegalArgumentException("Only outputType or outputJsonSchema can be set, not both.");
			}

			if (!StringUtils.hasText(this.outputJsonSchema) && this.outputType == null) {
				throw new IllegalArgumentException("Either outputType or outputJsonSchema must be set.");
			}

			if (this.outputType != null) {
				this.outputJsonSchema = JsonSchemaGenerator.generateForType(this.outputType);
			}

			return new StructuredOutputValidationAdvisor(this.advisorOrder,
					Objects.requireNonNull(this.outputJsonSchema), this.maxRepeatAttempts, this.jsonMapper);
		}

	}

	private record SchemaValidation(boolean success, String errorMessage) {

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Remove either the outputType or the outputJsonSchema call — keep one.
  2. If you want the generated schema plus tweaks, keep outputType only, or precompute generateForType(type), edit it, and pass that as outputJsonSchema instead.
  3. Search builder chains in your config for both method calls on the same advisor builder.

Example fix

// before
StructuredOutputValidationAdvisor.builder()
    .outputType(MyRecord.class)
    .outputJsonSchema(schemaString)
    .build();
// after
StructuredOutputValidationAdvisor.builder()
    .outputType(MyRecord.class)
    .build();
Defensive patterns

Strategy: validation

Validate before calling

StructuredOutputValidationAdvisor.Builder b = StructuredOutputValidationAdvisor.builder();
// ensure only one of the two is ever set in your builder helper
if (useType) b.outputType(MyRecord.class); else b.outputJsonSchema(schemaString);

Try / catch

try { advisorBuilder.build(); } catch (IllegalArgumentException e) { if (e.getMessage().startsWith("Only outputType or outputJsonSchema")) { /* remove one setter */ } throw e; }

Prevention

When it happens

Trigger: Calling .outputType(SomeClass.class) and .outputJsonSchema("...") on the same Builder before build().

Common situations: Adding an explicit schema to refine an existing type-based config, merging builder defaults with user-supplied schema, or copy-pasted builder code where both sources of truth were left in place.

Related errors


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