OpenFeign/feign · error · IllegalArgumentException

Not an iterator type

Error message

Not an iterator type ${rawType}

What it means

Jackson3IteratorDecoder requires the raw type of the declared return type to be exactly java.util.Iterator. Any other parameterized type (List<T>, Page<T>, etc.) throws IllegalArgumentException('Not an iterator type ...').

Solutions

  1. Change the return type to Iterator<ItemDto> if streaming is desired
  2. Keep List<ItemDto> and use Jackson3Decoder instead of the iterator decoder
  3. Register Jackson3IteratorDecoder only for specific methods/targets that genuinely stream Iterator<T>
  4. If wrapping in a custom container, implement a dedicated Decoder rather than reusing this one

Example fix

// before
@Get("/items") List<ItemDto> getItems(); // with Jackson3IteratorDecoder
// after
@Get("/items") Iterator<ItemDto> getItems(); // with Jackson3IteratorDecoder
Defensive patterns

Strategy: type-guard

Validate before calling

Type t = method.getGenericReturnType();
if (t instanceof ParameterizedType
    && ((ParameterizedType) t).getRawType() != java.util.Iterator.class) {
  throw new IllegalStateException("Jackson3IteratorDecoder needs Iterator<T>, got: " + t);
}

Type guard

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

Try / catch

try {
  return decoder.decode(response, type);
} catch (IllegalArgumentException e) {
  if (e.getMessage().startsWith("Not an iterator type")) {
    return fallbackListDecoder.decode(response, type);
  }
  throw e;
}

Prevention

When it happens

Trigger: Declaring a Feign method returning List<ItemDto>, Set<ItemDto>, or any other generic type and decoding with Jackson3IteratorDecoder; the guard Iterator.class.equals(parameterizedType.getRawType()) fails at decode time.

Common situations: Registering the iterator decoder as the global decoder while most endpoints return List<T>; switching a method's return type from Iterator<T> to List<T> without changing the decoder configuration.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at jackson3/src/main/java/feign/jackson3/Jackson3IteratorDecoder.java:104

      }
      reader.reset();
      return new Jackson3Iterator<Object>(
          actualIteratorTypeArgument(type), mapper, response, reader);
    } catch (JacksonException 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 Jackson3IteratorDecoder create() {
    return create(Collections.<JacksonModule>emptyList());
  }

  public static Jackson3IteratorDecoder create(Iterable<JacksonModule> modules) {
    return new Jackson3IteratorDecoder(
        JsonMapper.builder()
            .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
            // Disable FAIL_ON_TRAILING_TOKENS for iterator: we read a JSON array element by
            // element, so there are always "trailing tokens" (the remaining array elements)
            .disable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS)
            .addModules(modules)
            .build());

View on GitHub (pinned to e2a1e27560)