{"record":{"id":"3ce937147ecdf1f4","repo":"OpenFeign/feign","slug":"cannot-generate-exception-check-constructor-para","errorCode":null,"errorMessage":"Cannot generate exception - check constructor parameter types (are headers Map<String,Collection<String>> or is something causing an exception on construction?)","messagePattern":"Cannot generate exception - check constructor parameter types \\(are headers Map<String,Collection<String>> or is something causing an exception on construction\\?\\)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"annotation-error-decoder/src/main/java/feign/error/ExceptionGenerator.java","lineNumber":198,"sourceCode":"      ExceptionGenerator generator =\n          new ExceptionGenerator(\n              bodyIndex,\n              requestIndex,\n              headerMapIndex,\n              numOfParams,\n              bodyType,\n              exceptionType,\n              responseBodyDecoder);\n\n      validateGeneratorCanBeUsedToGenerateExceptions(generator);\n      return generator;\n    }\n\n    private void validateGeneratorCanBeUsedToGenerateExceptions(ExceptionGenerator generator) {\n      try {\n        generator.createException(TEST_RESPONSE);\n      } catch (Exception e) {\n        throw new IllegalStateException(\n            \"Cannot generate exception - check constructor parameter types (are headers\"\n                + \" Map<String,Collection<String>> or is something causing an exception on\"\n                + \" construction?)\",\n            e);\n      }\n    }\n\n    private Constructor<? extends Exception> getConstructor(\n        Class<? extends Exception> exceptionClass) {\n      Constructor<? extends Exception> preferredConstructor = null;\n      for (Constructor<?> constructor : exceptionClass.getConstructors()) {\n\n        FeignExceptionConstructor exceptionConstructor =\n            constructor.getAnnotation(FeignExceptionConstructor.class);\n        if (exceptionConstructor == null) {\n          continue;\n        }\n        Class<?>[] parameterTypes = constructor.getParameterTypes();","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/OpenFeign/feign/blob/e2a1e27560a1e68840c34f031afca88b36096e30/annotation-error-decoder/src/main/java/feign/error/ExceptionGenerator.java#L180-L216","documentation":"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>>).","triggerScenarios":"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).","commonSituations":"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.","solutions":["Fix the constructor body so it tolerates null/empty body and raw non-JSON content without throwing","Match constructor parameter types exactly to supported ones: (Response), (String body), (int status), (Map<String,Collection<String>> headers), or combinations in supported orders","Inspect the cause attached to this IllegalStateException — it contains the real exception thrown inside your constructor","Simplify to a constructor accepting only (int status, String body) if unsure"],"exampleFix":"// before\npublic class ApiError extends RuntimeException {\n  public ApiError(int status, Map<String, String> headers, String body) {\n    super(parse(body).get(\"message\")); // throws on empty body\n  }\n}\n// after\npublic class ApiError extends RuntimeException {\n  public ApiError(int status, Map<String, Collection<String>> headers, String body) {\n    super(body != null ? extractMessage(body) : (\"HTTP \" + status));\n  }\n}","handlingStrategy":"validation","validationCode":"// unit-test your exception constructor the way Feign does\nnew ApiError(500, null, Collections.<String, Collection<String>>emptyMap());","typeGuard":null,"tryCatchPattern":"try { api.call(); } catch (IllegalStateException e) {\n  if (e.getCause() != null) { log.error(\"constructor threw\", e.getCause()); }\n}","preventionTips":["Never let the exception constructor throw — guard all parsing and validation","Use supported parameter types: int status, String body, Map<String,Collection<String>> headers, Response","Handle null body and non-JSON error payloads in the constructor","Write a test invoking the constructor with an empty response"],"tags":["java","feign","reflection","constructor"],"backgroundTag":"invalid-constructor-argument","analyzedSha":"e2a1e27560a1e68840c34f031afca88b36096e30","analyzedAt":"2026-09-10T12:37:37.238Z","contentChangedAt":"2026-09-10T12:37:37.238Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}