OpenFeign/feign · error · IllegalArgumentException

Not an iterator type

Error message

Not an iterator type ${rawType}

What it means

Companion check in actualIteratorTypeArgument: the type is parameterized but its raw type is not java.util.Iterator, so the decoder cannot stream it and throws IllegalArgumentException 'Not an iterator type X'.

Solutions

  1. Return Iterator<T> from methods handled by JacksonIteratorDecoder.
  2. Register a composed decoder: new JacksonDecoder() for normal types and JacksonIteratorDecoder for Iterator<T> methods (or use the auto-detecting setup).
  3. Only set JacksonIteratorDecoder per-method/per-client where streaming is intended.
  4. Check the declared return type's generic raw type.

Example fix

// before
.decoder(new JacksonIteratorDecoder()) // used with List<User> return types
// after
.decoder(new Decoder.Default(new JacksonDecoder(), new JacksonIteratorDecoder()));
// and declare streaming methods as Iterator<User>
Defensive patterns

Strategy: type-guard

Validate before calling

static boolean isIteratorType(Type type) {
  return type instanceof ParameterizedType
      && java.util.Iterator.class.equals(((ParameterizedType) type).getRawType());
}

Type guard

static boolean suitableForIteratorDecoder(java.lang.reflect.Method m) {
  Type t = m.getGenericReturnType();
  return t instanceof ParameterizedType && java.util.Iterator.class.equals(((ParameterizedType) t).getRawType());
}

Try / catch

try {
  return feignClient.call();
} catch (feign.codec.DecodeException e) {
  if (e.getCause() instanceof IllegalArgumentException && e.getCause().getMessage().startsWith("Not an iterator type")) {
    throw new IllegalStateException("Use the standard JacksonDecoder for non-Iterator return types", e);
  }
  throw e;
}

Prevention

When it happens

Trigger: Using JacksonIteratorDecoder with a method returning List<User>, Collection<User>, or any other ParameterizedType that is not Iterator<T>.

Common situations: Applying the iterator decoder globally to all methods (e.g. in Feign.builder().decoder(JacksonIteratorDecoder.create())) while most methods return List<T>; migrating methods without switching back to the standard decoder.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of OpenFeign/feign@e2a1e27560 (2026-09-10). Data as JSON: /api/errors/3bc8c8035d7e0363. Report an issue: GitHub.

Appendix: source

Thrown at jackson/src/main/java/feign/jackson/JacksonIteratorDecoder.java:101

      }
      reader.reset();
      return new JacksonIterator<Object>(
          actualIteratorTypeArgument(type), mapper, response, reader);
    } catch (RuntimeJsonMappingException e) {
      if (e.getCause() != null && e.getCause() instanceof IOException) {
        throw IOException.class.cast(e.getCause());
      }
      throw e;
    }
  }

  private static Type actualIteratorTypeArgument(Type type) {
    if (!(type instanceof ParameterizedType)) {
      throw new IllegalArgumentException("Not supported type " + type.toString());
    }
    ParameterizedType parameterizedType = (ParameterizedType) type;
    if (!Iterator.class.equals(parameterizedType.getRawType())) {
      throw new IllegalArgumentException(
          "Not an iterator type " + parameterizedType.getRawType().toString());
    }
    return ((ParameterizedType) type).getActualTypeArguments()[0];
  }

  public static JacksonIteratorDecoder create() {
    return create(Collections.<Module>emptyList());
  }

  public static JacksonIteratorDecoder create(Iterable<Module> modules) {
    return new JacksonIteratorDecoder(
        new ObjectMapper()
            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
            .registerModules(modules));
  }

  public static JacksonIteratorDecoder create(ObjectMapper objectMapper) {
    return new JacksonIteratorDecoder(objectMapper);

View on GitHub (pinned to e2a1e27560)