OpenFeign/feign · error · EncodeException

${e.getMessage()}

Error message

${e.getMessage()}

What it means

Feign's Jackson3Encoder wraps any JacksonException thrown while serializing the request body into a feign EncodeException, keeping the original Jackson message as the message. This means the ObjectMapper could not convert your object into JSON bytes for the given declared body type. It is a wrapper around an underlying serialization problem, not a network issue.

Solutions

  1. Read the wrapped cause (getCause()) - the JacksonException message names the exact property/class that failed
  2. Ensure the DTO has public getters or annotate/enable field visibility (mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY))
  3. Register needed Jackson modules (JavaTimeModule, Jdk8Module, etc.) on the ObjectMapper passed to Jackson3Encoder.create
  4. Verify the Type passed to encode matches the actual runtime object's type (avoid raw Object bodies)
  5. If serializing a third-party type, add a custom JsonSerializer or a mixin

Example fix

// before
Feign.builder().encoder(new Jackson3Encoder(new ObjectMapper()));
// after
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
Feign.builder().encoder(new Jackson3Encoder(mapper));
Defensive patterns

Strategy: try-catch

Validate before calling

// before encoding
if (object == null) throw new IllegalArgumentException("body must not be null");
if (!mapper.canSerialize(object.getClass())) {
  throw new IllegalStateException("ObjectMapper cannot serialize " + object.getClass());
}

Type guard

static boolean isEncodable(ObjectMapper mapper, Object o) {
  return o != null && mapper.canSerialize(o.getClass());
}

Try / catch

try {
  encoder.encode(object, bodyType, template);
} catch (EncodeException e) {
  Throwable root = e;
  while (root.getCause() != null) root = root.getCause();
  throw new IllegalStateException("Jackson serialization failed: " + root.getMessage(), e);
}

Prevention

When it happens

Trigger: Calling encode() on Jackson3Encoder when mapper.writerFor(javaType).writeValueAsBytes(object) throws a JacksonException - e.g. serializing an object with no accessible properties, an invalid JavaType derived from a generic Type, self-referential structures exceeding max depth, or a custom serializer throwing.

Common situations: Encoding POJOs without getters and without field visibility configured; using types like Object or raw generics that Jackson cannot resolve; missing jackson-databind serializers for third-party types (Instant, Optional without modules); cyclic object graphs.

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 OpenFeign/feign@e2a1e27560 (2026-09-10). Data as JSON: /api/errors/4b86a028785dd7dd. Report an issue: GitHub.

Appendix: source

Thrown at jackson3/src/main/java/feign/jackson3/Jackson3Encoder.java:61

        JsonMapper.builder()
            .changeDefaultPropertyInclusion(
                incl -> incl.withValueInclusion(JsonInclude.Include.NON_NULL))
            .enable(SerializationFeature.INDENT_OUTPUT)
            .addModules(modules)
            .build());
  }

  public Jackson3Encoder(JsonMapper mapper) {
    this.mapper = mapper;
  }

  @Override
  public void encode(Object object, Type bodyType, RequestTemplate template) {
    try {
      JavaType javaType = mapper.getTypeFactory().constructType(bodyType);
      template.body(mapper.writerFor(javaType).writeValueAsBytes(object), Util.UTF_8);
    } catch (JacksonException e) {
      throw new EncodeException(e.getMessage(), e);
    }
  }

  @Override
  public boolean canEncode(Object object, Type bodyType, RequestTemplate template) {
    return Util.isJsonContentType(template);
  }
}

View on GitHub (pinned to e2a1e27560)