OpenFeign/feign · error · IllegalStateException

Cannot generate exception - check constructor parameter…

Error message

Cannot generate exception - check constructor parameter types (are headers Map<String,Collection<String>> or is something causing an exception on construction?)

What it means

Thrown by ExceptionGenerator.validateGeneratorCanBeUsedToGenerateExceptions during build() as a dry-run sanity check: it invokes the custom exception's constructor against a test response, and any exception escaping the constructor triggers this error. It means the exception class's constructor signature or constructor body is incompatible with the arguments Feign supplies (status, body, headers Map<String,Collection<String>>).

Solutions

  1. Fix the constructor body so it tolerates null/empty body and raw non-JSON content without throwing
  2. Match constructor parameter types exactly to supported ones: (Response), (String body), (int status), (Map<String,Collection<String>> headers), or combinations in supported orders
  3. Inspect the cause attached to this IllegalStateException — it contains the real exception thrown inside your constructor
  4. Simplify to a constructor accepting only (int status, String body) if unsure

Example fix

// before
public class ApiError extends RuntimeException {
  public ApiError(int status, Map<String, String> headers, String body) {
    super(parse(body).get("message")); // throws on empty body
  }
}
// after
public class ApiError extends RuntimeException {
  public ApiError(int status, Map<String, Collection<String>> headers, String body) {
    super(body != null ? extractMessage(body) : ("HTTP " + status));
  }
}
Defensive patterns

Strategy: validation

Validate before calling

// unit-test your exception constructor the way Feign does
new ApiError(500, null, Collections.<String, Collection<String>>emptyMap());

Try / catch

try { api.call(); } catch (IllegalStateException e) {
  if (e.getCause() != null) { log.error("constructor threw", e.getCause()); }
}

Prevention

When it happens

Trigger: An exception class annotated with @FeignExceptionConstructor whose constructor throws during construction (e.g. NPE parsing the body string), or whose parameter types force an unconvertible argument (e.g. constructor takes int status but receives a value that cannot be coerced, or wrong headers generic type).

Common situations: Constructor parses the raw body with JSON parsing that fails on empty/HTML bodies; headers declared as Map<String,String> instead of Map<String,Collection<String>>; constructor validation (Objects.requireNonNull / custom precondition) rejects the test response's null body.

Related errors


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

Appendix: source

Thrown at annotation-error-decoder/src/main/java/feign/error/ExceptionGenerator.java:198

      ExceptionGenerator generator =
          new ExceptionGenerator(
              bodyIndex,
              requestIndex,
              headerMapIndex,
              numOfParams,
              bodyType,
              exceptionType,
              responseBodyDecoder);

      validateGeneratorCanBeUsedToGenerateExceptions(generator);
      return generator;
    }

    private void validateGeneratorCanBeUsedToGenerateExceptions(ExceptionGenerator generator) {
      try {
        generator.createException(TEST_RESPONSE);
      } catch (Exception e) {
        throw new IllegalStateException(
            "Cannot generate exception - check constructor parameter types (are headers"
                + " Map<String,Collection<String>> or is something causing an exception on"
                + " construction?)",
            e);
      }
    }

    private Constructor<? extends Exception> getConstructor(
        Class<? extends Exception> exceptionClass) {
      Constructor<? extends Exception> preferredConstructor = null;
      for (Constructor<?> constructor : exceptionClass.getConstructors()) {

        FeignExceptionConstructor exceptionConstructor =
            constructor.getAnnotation(FeignExceptionConstructor.class);
        if (exceptionConstructor == null) {
          continue;
        }
        Class<?>[] parameterTypes = constructor.getParameterTypes();

View on GitHub (pinned to e2a1e27560)