spring-projects/spring-security · error · HttpMessageNotWritableException

This converter cannot write a…

Error message

This converter cannot write a RelyingPartyRegistration.Builder

What it means

OpenSamlRelyingPartyRegistrationBuilderHttpMessageConverter only supports reading (converting metadata bytes into a RelyingPartyRegistration.Builder). Its write operation is intentionally unimplemented and always throws HttpMessageNotWritableException. If Spring MVC tries to serialize a RelyingPartyRegistration.Builder as an HTTP response body, this error occurs.

Solutions

  1. Call .build() on the RelyingPartyRegistration.Builder and return the RelyingPartyRegistration (or a DTO/metadata view) instead
  2. If you need to emit SP metadata, use OpenSaml metadata generation endpoints (e.g. spring.security saml metadata filter) rather than this converter
  3. Return a different response representation (Map, ResponseEntity<String>) so this converter isn't selected

Example fix

// before
@GetMapping("/registration")
public RelyingPartyRegistration.Builder registration() { return builder; }
// after
@GetMapping("/registration")
public RelyingPartyRegistration registration() { return builder.build(); }
Defensive patterns

Strategy: type-guard

Validate before calling

Object body = controllerReturnValue;
if (body instanceof RelyingPartyRegistration.Builder) {
    throw new IllegalStateException("Return RelyingPartyRegistration, not its Builder");
}

Type guard

boolean isWritable(Object body) {
    return !(body instanceof RelyingPartyRegistration.Builder);
}

Try / catch

// Avoid at runtime by design; if writing a generic handler:
try {
    converter.write(builder, contentType, outputMessage);
} catch (HttpMessageNotWritableException ex) {
    throw new UnsupportedOperationException("Read-only converter; build the registration first", ex);
}

Prevention

When it happens

Trigger: Returning a RelyingPartyRegistration.Builder (or a type resolving to this converter) from a @RestController method, or calling converter.write(...) directly; HttpMessageNotWritableException thrown from write().

Common situations: Controller accidentally returns the Builder instead of a built RelyingPartyRegistration or a DTO; developer assumes the converter is bidirectional; misconfigured message converters pick this converter for the response.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10). Data as JSON: /api/errors/18c105fc830d34ad. Report an issue: GitHub.

Appendix: source

Thrown at saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/registration/OpenSamlRelyingPartyRegistrationBuilderHttpMessageConverter.java:91

	public boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType) {
		return false;
	}

	@Override
	public List<MediaType> getSupportedMediaTypes() {
		return Arrays.asList(MediaType.APPLICATION_XML, MediaType.TEXT_XML);
	}

	@Override
	public RelyingPartyRegistration.Builder read(Class<? extends RelyingPartyRegistration.Builder> clazz,
			HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
		return RelyingPartyRegistrations.fromMetadata(inputMessage.getBody());
	}

	@Override
	public void write(RelyingPartyRegistration.Builder builder, @Nullable MediaType contentType,
			HttpOutputMessage outputMessage) throws HttpMessageNotWritableException {
		throw new HttpMessageNotWritableException("This converter cannot write a RelyingPartyRegistration.Builder");
	}

}

View on GitHub (pinned to 96852e8860)