spring-projects/spring-security · error · HttpMessageNotWritableException
An error occurred writing the Token Introspection Response:
Error message
An error occurred writing the Token Introspection Response: + ex.getMessage()
What it means
OAuth2TokenIntrospectionHttpMessageConverter.writeInternal wraps any exception raised while converting OAuth2TokenIntrospection to its response parameter Map and writing it as JSON to the HTTP output stream. Failures in tokenIntrospectionParametersConverter.convert() or jsonMessageConverter.write() are rethrown as org.springframework.http.converter.HttpMessageNotWritableException with the cause preserved. It indicates the token introspection response could not be serialized and returned to the caller.
Source
Thrown at oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/http/converter/OAuth2TokenIntrospectionHttpMessageConverter.java:107
return this.tokenIntrospectionConverter.convert(tokenIntrospectionParameters);
}
catch (Exception ex) {
throw new HttpMessageNotReadableException(
"An error occurred reading the Token Introspection Response: " + ex.getMessage(), ex, inputMessage);
}
}
@Override
protected void writeInternal(OAuth2TokenIntrospection tokenIntrospection, HttpOutputMessage outputMessage)
throws HttpMessageNotWritableException {
try {
Map<String, Object> tokenIntrospectionResponseParameters = this.tokenIntrospectionParametersConverter
.convert(tokenIntrospection);
this.jsonMessageConverter.write(tokenIntrospectionResponseParameters, STRING_OBJECT_MAP.getType(),
MediaType.APPLICATION_JSON, outputMessage);
}
catch (Exception ex) {
throw new HttpMessageNotWritableException(
"An error occurred writing the Token Introspection Response: " + ex.getMessage(), ex);
}
}
/**
* Sets the {@link Converter} used for converting the Token Introspection Response
* parameters to an {@link OAuth2TokenIntrospection}.
* @param tokenIntrospectionConverter the {@link Converter} used for converting to an
* {@link OAuth2TokenIntrospection}
*/
public final void setTokenIntrospectionConverter(
Converter<Map<String, Object>, OAuth2TokenIntrospection> tokenIntrospectionConverter) {
Assert.notNull(tokenIntrospectionConverter, "tokenIntrospectionConverter cannot be null");
this.tokenIntrospectionConverter = tokenIntrospectionConverter;
}
/**
* Sets the {@link Converter} used for converting an {@link OAuth2TokenIntrospection}View on GitHub (pinned to 96852e8860)
Solutions
- Inspect ex.getCause() to identify whether the failure is serialization, converter, or I/O related and fix that root cause.
- Ensure a functioning JSON HttpMessageConverter (MappingJackson2HttpMessageConverter) is available or set via setJsonMessageConverter.
- Confirm the OAuth2TokenIntrospection instance and any additional parameters contain only JSON-serializable values with correct types (e.g. boolean active).
- Review custom code registered via setTokenIntrospectionParametersConverter for exceptions on your data.
- Handle client-disconnect I/O errors as benign — log at debug and do not retry writing to a committed response.
Example fix
// before
introspection.set("scope_grants", someNonSerializableDomainObject);
// after
introspection.set("scope_grants", objectMapper.valueToTree(someDomainObject)); // serialize to JSON-compatible form first Defensive patterns
Strategy: try-catch
Validate before calling
// before writing assert tokenIntrospection.isActive() != null || tokenIntrospection.getParameters().isEmpty(); objectMapper.writeValueAsString(tokenIntrospection.getParameters()); // fail fast on unserializable claims
Try / catch
try {
converter.write(tokenIntrospection, MediaType.APPLICATION_JSON, outputMessage);
} catch (HttpMessageNotWritableException e) {
logger.error("Failed to write token introspection response", e.getCause());
}
// do not rethrow to a committed servlet response; log and return Prevention
- Serialize custom claim values to Jackson-compatible types before adding them to introspection.
- Keep a working MappingJackson2HttpMessageConverter in the converter chain.
- Treat broken-pipe/client-disconnect write errors as debug-level noise.
- Unit-test writing introspection responses including edge cases (inactive token, extra claims).
When it happens
Trigger: Calling OAuth2TokenIntrospectionHttpMessageConverter.write() (via writeInternal) when tokenIntrospectionParametersConverter.convert() throws (invalid introspection state) or jsonMessageConverter.write() fails to serialize the Map<String,Object> to JSON (no JSON converter, broken output stream, unserializable custom claim).
Common situations: An introspection endpoint implementation adds a custom claim value the ObjectMapper cannot serialize; the client disconnected before the response was fully written (broken pipe); the JSON HttpMessageConverter was replaced/removed in configuration; a custom Converter set via setTokenIntrospectionParametersConverter throws on certain introspection instances.
Understand the failure class
Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.
Related errors
- An error occurred writing the OAuth 2.0 Authorization Server
- An error occurred writing the OAuth 2.0 Client Registration:
- An error occurred reading the Token Introspection Response:
- Unable to create an {OAuth2AuthorizedClientManager} bean. Ex
- invalid_dpop_proof
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/65287acb9ec48582.
Report an issue: GitHub.