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

  1. Inspect ex.getCause() to identify whether the failure is serialization, converter, or I/O related and fix that root cause.
  2. Ensure a functioning JSON HttpMessageConverter (MappingJackson2HttpMessageConverter) is available or set via setJsonMessageConverter.
  3. Confirm the OAuth2TokenIntrospection instance and any additional parameters contain only JSON-serializable values with correct types (e.g. boolean active).
  4. Review custom code registered via setTokenIntrospectionParametersConverter for exceptions on your data.
  5. 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

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


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