{"record":{"id":"c687c4d220ae9e75","repo":"spring-projects/spring-security","slug":"an-error-occurred-reading-the-token-introspection","errorCode":null,"errorMessage":"An error occurred reading the Token Introspection Response: + ex.getMessage()","messagePattern":"An error occurred reading the Token Introspection Response: \\+ ex\\.getMessage\\(\\)","errorType":"http","errorClass":"HttpMessageNotReadableException","httpStatus":400,"severity":"error","filePath":"oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/http/converter/OAuth2TokenIntrospectionHttpMessageConverter.java","lineNumber":92,"sourceCode":"\t\tthis.jsonMessageConverter = converter;\n\t}\n\n\t@Override\n\tprotected boolean supports(Class<?> clazz) {\n\t\treturn OAuth2TokenIntrospection.class.isAssignableFrom(clazz);\n\t}\n\n\t@Override\n\t@SuppressWarnings(\"unchecked\")\n\tprotected OAuth2TokenIntrospection readInternal(Class<? extends OAuth2TokenIntrospection> clazz,\n\t\t\tHttpInputMessage inputMessage) throws HttpMessageNotReadableException {\n\t\ttry {\n\t\t\tMap<String, Object> tokenIntrospectionParameters = (Map<String, Object>) this.jsonMessageConverter\n\t\t\t\t.read(STRING_OBJECT_MAP.getType(), null, inputMessage);\n\t\t\treturn this.tokenIntrospectionConverter.convert(tokenIntrospectionParameters);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new HttpMessageNotReadableException(\n\t\t\t\t\t\"An error occurred reading the Token Introspection Response: \" + ex.getMessage(), ex, inputMessage);\n\t\t}\n\t}\n\n\t@Override\n\tprotected void writeInternal(OAuth2TokenIntrospection tokenIntrospection, HttpOutputMessage outputMessage)\n\t\t\tthrows HttpMessageNotWritableException {\n\t\ttry {\n\t\t\tMap<String, Object> tokenIntrospectionResponseParameters = this.tokenIntrospectionParametersConverter\n\t\t\t\t.convert(tokenIntrospection);\n\t\t\tthis.jsonMessageConverter.write(tokenIntrospectionResponseParameters, STRING_OBJECT_MAP.getType(),\n\t\t\t\t\tMediaType.APPLICATION_JSON, outputMessage);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new HttpMessageNotWritableException(\n\t\t\t\t\t\"An error occurred writing the Token Introspection Response: \" + ex.getMessage(), ex);\n\t\t}\n\t}","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/http/converter/OAuth2TokenIntrospectionHttpMessageConverter.java#L74-L110","documentation":"OAuth2TokenIntrospectionHttpMessageConverter.readInternal wraps any exception raised while reading a token introspection response body as JSON and converting it to an OAuth2TokenIntrospection. The body is parsed into a Map<String,Object> by the JSON converter and then mapped by tokenIntrospectionConverter.convert(); any parse or mapping failure is rethrown as org.springframework.http.converter.HttpMessageNotReadableException with the cause attached. This means the introspection response could not be read into the typed model.","triggerScenarios":"Calling OAuth2TokenIntrospectionHttpMessageConverter.read() (via readInternal) when the response body is not valid JSON (HTML error page, empty body, wrong Content-Type), the JSON converter throws, or tokenIntrospectionConverter.convert() rejects the parameters (e.g. active flag not boolean, invalid claim types).","commonSituations":"The introspection endpoint returns 401/404 with an HTML or empty body that still gets passed to the converter; a proxy/gateway rewrites Content-Type so the Jackson converter refuses the read; an older or non-conformant authorization server omits required claims or sends them with unexpected types; custom converters configured via setTokenIntrospectionConverter are too strict.","solutions":["Check the exception cause to distinguish JSON syntax failure from field-mapping failure; log the raw response body.","Check the HTTP status before parsing — only feed 2xx application/json responses to the converter.","Ensure the introspection endpoint returns RFC 7662-compliant JSON (boolean active, correct claim types).","Verify a JSON-capable converter is set via setJsonMessageConverter and Content-Type is application/json.","Correct or relax a custom tokenIntrospectionConverter if it rejects otherwise-valid claims."],"exampleFix":"// before\nClientHttpResponse resp = execute(introspectionRequest);\nOAuth2TokenIntrospection i = converter.read(OAuth2TokenIntrospection.class, resp); // throws on 401 HTML body\n// after\nClientHttpResponse resp = execute(introspectionRequest);\nif (resp.getStatusCode() != HttpStatus.OK) {\n  throw new OAuth2IntrospectionException(\"Introspection failed: \" + resp.getStatusCode());\n}\nOAuth2TokenIntrospection i = converter.read(OAuth2TokenIntrospection.class, resp);","handlingStrategy":"validation","validationCode":"// before reading\nif (response.getStatusCode() != HttpStatus.OK) throw new OAuth2IntrospectionException(\"bad status \" + response.getStatusCode());\nif (!response.getHeaders().getContentType().isCompatibleWith(MediaType.APPLICATION_JSON)) throw new OAuth2IntrospectionException(\"non-JSON body\");","typeGuard":null,"tryCatchPattern":"try {\n  return converter.read(OAuth2TokenIntrospection.class, response);\n} catch (HttpMessageNotReadableException e) {\n  logger.warn(\"Unreadable introspection response: {}\", e.getCause().toString());\n  return OAuth2TokenIntrospection.builder().active(false).build(); // fail closed\n}","preventionTips":["Fail closed (treat token as inactive) when the introspection response cannot be parsed.","Reject non-2xx and non-JSON responses before parsing.","Confirm the introspection endpoint is RFC 7662 compliant (boolean active, correct claim types).","Watch for proxies/gateways rewriting Content-Type or replacing bodies with HTML error pages."],"tags":["spring-security","oauth2","token-introspection","json-parse"],"backgroundTag":"invalid-json-response","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}