OpenFeign/feign · error · EncodeException

Failure encoding object into query map

Error message

Failure encoding object into query map

What it means

BeanQueryMapEncoder converts a bean-style object into a query-parameter map by reading its properties via the JavaBeans Introspector. If reflection on the bean fails — a getter is not accessible, introspection of the class fails, or the underlying getter throws — Feign wraps the cause in EncodeException with this message.

Solutions

  1. Fix or remove the getter on the query-map bean that throws the wrapped InvocationTargetException
  2. Ensure query-map objects are proper JavaBeans: public class with public no-arg constructor and public getters
  3. Catch EncodeException around the Feign call and inspect getCause() to identify which property failed
  4. Make the bean class/methods accessible (public) if IllegalAccessException is the cause

Example fix

// before
Feign.builder().queryMapEncoder(new BeanQueryMapEncoder())
  .target(Api.class, "https://api");
// used with a class whose getter throws:
public class Params { public String getQ() { throw new IllegalStateException("uninitialized"); } }
// after
public class Params {
  private String q = "";
  public String getQ() { return q; } // getter must not throw
  public void setQ(String q) { this.q = q; }
}
Defensive patterns

Strategy: try-catch

Validate before calling

for (PropertyDescriptor pd : Introspector.getBeanInfo(params.getClass()).getPropertyDescriptors()) {
  if (pd.getReadMethod() == null || !Modifier.isPublic(pd.getReadMethod().getDeclaringClass().getModifiers()))
    throw new IllegalStateException("query-map bean property not readable: " + pd.getName());
}

Type guard

boolean isValidQueryMapBean(Object o) {
  return o != null && Modifier.isPublic(o.getClass().getModifiers());
}

Try / catch

try {
  api.search(params);
} catch (EncodeException e) {
  throw new IllegalArgumentException("bad query map bean: " + e.getCause(), e);
}

Prevention

When it happens

Trigger: Calling Feign with a @QueryMap-bound bean whose getters throw, whose property descriptors cannot be introspected (IntrospectionException), or whose getter method is inaccessible to the encoder (IllegalAccessException / InvocationTargetException).

Common situations: Passing non-bean or oddly-shaped objects (no public getters) as @QueryMap; beans with getter methods that throw NPEs on internal state; running under a SecurityManager/strict module access that blocks reflective getter calls; class changes after introspection metadata was cached.

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/2138417451662ede. Report an issue: GitHub.

Appendix: source

Thrown at core/src/main/java/feign/querymap/BeanQueryMapEncoder.java:60

  public Map<String, Object> encode(Object object) throws EncodeException {
    if (object == null) {
      return Collections.emptyMap();
    }
    try {
      ObjectParamMetadata metadata = getMetadata(object.getClass());
      Map<String, Object> propertyNameToValue = new HashMap<String, Object>();
      for (PropertyDescriptor pd : metadata.objectProperties) {
        Method method = pd.getReadMethod();
        Object value = method.invoke(object);
        if (value != null && value != object) {
          Param alias = method.getAnnotation(Param.class);
          String name = alias != null ? alias.value() : pd.getName();
          propertyNameToValue.put(name, value);
        }
      }
      return propertyNameToValue;
    } catch (IllegalAccessException | IntrospectionException | InvocationTargetException e) {
      throw new EncodeException("Failure encoding object into query map", e);
    }
  }

  private ObjectParamMetadata getMetadata(Class<?> objectType) throws IntrospectionException {
    ObjectParamMetadata metadata = classToMetadata.get(objectType);
    if (metadata == null) {
      metadata = ObjectParamMetadata.parseObjectType(objectType);
      classToMetadata.put(objectType, metadata);
    }
    return metadata;
  }

  private static class ObjectParamMetadata {

    private final List<PropertyDescriptor> objectProperties;

    private ObjectParamMetadata(List<PropertyDescriptor> objectProperties) {
      this.objectProperties = Collections.unmodifiableList(objectProperties);

View on GitHub (pinned to e2a1e27560)