Let's get started with a Microservice Architecture with Spring Cloud:
Handle “No Suitable HttpMessageConverter” in Spring RestTemplate
Last updated: April 7, 2026
1. Introduction
When consuming RESTful services in Spring, RestTemplate is a reliable workhorse for synchronous HTTP communication. However, one of the most common and frustrating hurdles developers face is the RestClientException. Specifically, the following error message:
Could not extract response: no suitable HttpMessageConverter found for response type and content type...
This error typically occurs when the client receives a response that it doesn’t know how to deserialize into the desired Java object. In this article, we’ll explore why this happens and how to configure our application to handle non-standard API responses effectively without encountering any such errors.
2. Project Setup
To get started, we’ll need the standard Spring Boot Starter Web dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>4.0.5</version>
</dependency>
For JSON processing, Spring Boot includes Jackson by default. To better understand it, we’ll ensure jackson-databind is on our classpath, as it provides the underlying logic for the MappingJackson2HttpMessageConverter.
3. Understanding and Identifying the Root Cause
To fix this error, we’ll first understand how Spring maps the raw HTTP response to Java objects. The issue is rarely with the data itself, but rather a mismatch in the expected communication protocol. We’ll now examine the internal conversion mechanism, identify common misleading media types, and learn how to inspect the actual response headers.
3.1. How RestTemplate Converts Responses
RestTemplate relies on a list of HttpMessageConverter beans to transform HTTP request and response bodies. When a response arrives, Spring looks at the Content-Type header sent by the server. It then iterates through its registered converters to find one that supports both that MediaType and the target Java class.
3.2. Common Mismatched Media Types
The issue usually isn’t that the data is invalid, but that the metadata is misleading. Many legacy or third-party APIs return valid JSON, but set the Content-Type header to something other than application/json. Common mismatched types include text/plain, text/javascript, and application/octet-stream.
The default MappingJackson2HttpMessageConverter only claims to support application/json and application/*+json. It ignores any other type of responses, leading to the “Could not extract response: no suitable HttpMessageConverter found for response type and content type” error.
3.3. Checking API Response Headers
To diagnose this, we must inspect the headers. If we can’t access external logs, we can enable debug logging for Spring Web in our application.properties:
logging.level.org.springframework.web.client.RestTemplate=DEBUG
This will reveal the exact Content-Type the server is providing, allowing us to target the specific mismatch.
4. Solving the Error: Configuration Strategies
In this section, we’ll create a config class named RestTemplateConverterConfig to inject the RestTemplate bean, which will help us resolve this error. The following section mentions the details on it:
4.1. Adding Support for Custom Media Types
The most surgical fix is to tell the Jackson converter to treat these uncommon media types as JSON. We can create an instance of MappingJackson2HttpMessageConverter and update its supported media types:
@Configuration
public class RestTemplateConverterConfig {
@Bean("specificMediaTypesRestTemplate")
public RestTemplate specificMediaTypesRestTemplate() {
RestTemplate restTemplate = new RestTemplate();
List<HttpMessageConverter<?>> converters = restTemplate.getMessageConverters();
MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
jsonConverter.setSupportedMediaTypes(Arrays.asList(
MediaType.APPLICATION_JSON,
MediaType.TEXT_PLAIN,
MediaType.valueOf("text/javascript")
));
converters.add(jsonConverter);
restTemplate.setMessageConverters(converters);
return restTemplate;
}
}
Here we explicitly list only the media types we expect to encounter. This keeps the converter’s scope narrow and intentional. Other unexpected content types, such as application/octet-stream, would still fail, which is often the desired behavior in a controlled environment.
4.2. Manually Registering Converters in RestTemplate
If we want a more permissive setup, within the same RestTemplateConverterConfig class, we’ll register another Jackson converter with MediaType.ALL. This instructs the RestTemplate to handle any content type the server returns:
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
List<HttpMessageConverter<?>> converters = restTemplate.getMessageConverters();
MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
jsonConverter.setSupportedMediaTypes(Collections.singletonList(MediaType.ALL));
converters.add(jsonConverter);
restTemplate.setMessageConverters(converters);
return restTemplate;
}
Here, we call the getMessageConverters() method and append to the existing list rather than replacing it. This preserves all the default converters Spring registers, such as those for String and byte[], and simply adds our custom Jackson converter at the end.
4.3. Using RestTemplate.exchange() With ParameterizedTypeReference
Sometimes the error arises because we are trying to deserialize into a generic collection, like List<User>. In this example, the User class is a simple POJO with id and name fields that Jackson maps from the JSON response.
Using getForObject() with List.class loses generic type information at runtime due to type erasure. Instead, we should use the restTemplate.exchange() method with a ParameterizedTypeReference:
ResponseEntity<List<User>> response = restTemplate.exchange(
"/users",
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<User>>() {}
);
The anonymous subclass of ParameterizedTypeReference captures the full generic type List<User> at compile time, giving Jackson enough information to correctly deserialize each element in the array into a User object.
5. Testing and Verification
To verify our configurations, we’ll use MockRestServiceServer. This allows us to simulate the exact mismatched header scenarios that typically trigger the RestClientException without needing a live external API.
5.1. Testing the Surgical Fix
In this first scenario, we use the @Qualifier to inject our specificMediaTypesRestTemplate. We’ll simulate a response that is explicitly labeled as text/plain. This proves that our surgical inclusion of that specific media type works as intended:
@Autowired
@Qualifier("specificMediaTypesRestTemplate")
private RestTemplate specificMediaTypesRestTemplate;
@Test
void givenSpecificMediaTypesRestTemplate_whenTextPlainResponse_thenDeserializeCorrectly() {
MockRestServiceServer mockServer = MockRestServiceServer.createServer(specificMediaTypesRestTemplate);
mockServer.expect(requestTo("/user"))
.andRespond(withSuccess("{\"id\":1,\"name\":\"Sudarshan\"}", MediaType.TEXT_PLAIN));
User user = specificMediaTypesRestTemplate.getForObject("/user", User.class);
assertNotNull(user);
assertEquals("Sudarshan", user.getName());
}
5.2. Testing the Permissive Fix
Next, we test the primary RestTemplate bean configured with MediaType.ALL. This test confirms that, by making the converter permissive, it ignores the misleading text/plain header and defaults to Jackson for deserialization.
@Test
void givenMockServer_whenTextPlainResponse_thenDeserializeCorrectly() {
MockRestServiceServer mockServer = MockRestServiceServer.createServer(restTemplate);
mockServer.expect(requestTo("/user"))
.andRespond(withSuccess("{\"id\":1,\"name\":\"Sudarshan\"}", MediaType.TEXT_PLAIN));
User user = restTemplate.getForObject("/user", User.class);
assertNotNull(user);
assertEquals("Sudarshan", user.getName());
}
5.3. Verifying Generic Type Resolution
Finally, we verify that our restTemplate.exchange() strategy correctly handles collections. Even with a mismatched text/plain header, the ParameterizedTypeReference ensures that the generic information List<User> is preserved during the conversion process:
@Test
void givenMockServer_whenTextPlainResponseForList_thenDeserializeWithParameterizedTypeReference() {
MockRestServiceServer mockServer = MockRestServiceServer.createServer(restTemplate);
mockServer.expect(requestTo("/users"))
.andRespond(
withSuccess(
"[{\"id\":1,\"name\":\"Sudarshan\"},{\"id\":2,\"name\":\"Baeldung\"}]",
MediaType.TEXT_PLAIN));
ResponseEntity<List<User>> response = restTemplate.exchange(
"/users",
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<User>>() {}
);
assertNotNull(response.getBody());
assertEquals(2, response.getBody().size());
assertEquals("Sudarshan", response.getBody().get(0).getName());
}
6. Conclusion
In this tutorial, we understood that the “No Suitable HttpMessageConverter” error is rarely a sign of broken data; it’s a communication breakdown between the server’s headers and the client’s expectations. By identifying the returned Content-Type and explicitly configuring our MappingJackson2HttpMessageConverter to support it, we can bridge this gap.
Whether you choose to support all media types via MediaType.ALL or strictly list the exceptions, like text/plain, understanding the converter registration process is key to building resilient Spring clients.
As always, the complete code samples used in this article are available over on GitHub.

















