OpenFeign/feign · error · EncodeException
Unable to encode ( ) ...
Error message
Unable to encode {bodyType} ({headers}) ... What it means
Feign's MultiEncoder iterates its registered PredicatedEncoders and throws this EncodeException when none of them declares it can encode the request body for the given bodyType. The message includes the body type and template headers, indicating the encoder chain lacks coverage for this request shape. It is thrown before any HTTP call is made.
Solutions
- Register a matching encoder, e.g. Feign.builder().encoder(new JacksonEncoder()) or add it to the MultiEncoder.Builder chain
- Add a fallback encoder (e.g. new Encoder.Default() which handles String/byte[]) as the last entry
- Check the body type in the message and confirm it is the type your interface method actually sends; align the method signature or encoder predicate
- Verify the relevant codec module (feign-jackson, feign-gson, etc.) is on the classpath
Example fix
// before
Feign.builder().decoder(new JacksonDecoder()).target(Api.class, url); // POST fails
// after
Feign.builder()
.encoder(new MultiEncoder.Builder().add(new JacksonEncoder()).add(new Encoder.Default()).build())
.decoder(new JacksonDecoder())
.target(Api.class, url); Defensive patterns
Strategy: validation
Validate before calling
// verify every @Body/@Param object type in the target interface has an encoder
for (Method m : apiInterface.getMethods()) {
Class<?> bodyType = bodyParamType(m);
if (bodyType != null && !encoders.stream().anyMatch(e -> e.canEncode(bodyType.newInstance(), bodyType, new RequestTemplate()))) {
throw new ConfigurationException("No encoder registered for " + bodyType);
}
} Try / catch
try {
return api.post(payload);
} catch (EncodeException e) {
if (e.getMessage().startsWith("Unable to encode")) {
throw new ClientConfigurationException("No encoder for body type: " + e.getMessage(), e);
}
throw e;
} Prevention
- Always register an encoder when the interface sends request bodies (JacksonEncoder/GsonEncoder/Encoder.Default)
- End MultiEncoder chains with Encoder.Default as a fallback for String/byte[] bodies
- Confirm the codec module dependency is present before wiring its encoder
- Review encoder coverage when changing an endpoint from form params to a body
When it happens
Trigger: Sending a request with a body (e.g. a @Body or @Param object) whose Java type (e.g. a POJO without a JSON encoder registered, or a Map with form encoding expected) matches no registered encoder's canEncode predicate in the MultiEncoder chain.
Common situations: Building a client with only a decoder but no encoder, then POSTing an object; forgetting to register JacksonEncoder/GsonEncoder; sending a raw String/byte[] when the registered encoder only handles JSON types; switching an endpoint from form params to a JSON body without updating encoders.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- Status Code [ ] has already been declared to throw [ ] and…
- Unable to decode response ( ) ...
- at least one decoder is required
- at least one encoder is required
- Failure encoding object into query map
AI-assisted analysis of OpenFeign/feign@e2a1e27560 (2026-09-10).
Data as JSON: /api/errors/ccc58da9249bafc0.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/feign/codec/MultiEncoder.java:109
/**
* Encodes using the first encoder that accepts the request.
*
* @param object {@inheritDoc}
* @param bodyType {@inheritDoc}
* @param template {@inheritDoc}
* @throws EncodeException when no encoder accepts the request, or the chosen one fails
*/
@Override
public void encode(Object object, Type bodyType, RequestTemplate template)
throws EncodeException {
for (PredicatedEncoder encoder : encoders) {
if (encoder.canEncode(object, bodyType, template)) {
encoder.encode(object, bodyType, template);
return;
}
}
throw new EncodeException(unableToEncode(bodyType, template));
}
private String unableToEncode(Type bodyType, RequestTemplate template) {
StringBuilder message =
new StringBuilder("Unable to encode ")
.append(bodyType == null ? "request body" : bodyType.getTypeName())
.append(" (")
.append(headers(template))
.append(')');
if (template.method() != null) {
message.append(" for ").append(template.method()).append(' ').append(template.path());
}
message.append(". Encoders tried, in order:");
appendTo(message, "\n ");
return message
.append("\nRegister an encoder that accepts it, or add a catch-all")
.append(" (EncoderPredicate.any()) last.")
.toString();View on GitHub (pinned to e2a1e27560)