ErrLookup › Background articles › IllegalArgumentException: When a Java Library Rejects the Argument You Handed It
IllegalArgumentException: When a Java Library Rejects the Argument You Handed It
IllegalArgumentException is the unchecked RuntimeException Java libraries throw when a method receives an argument that is the wrong value, wrong type, wrong shape, or wrong count. Developers meet it at trust boundaries — configuration parsing, script compilation, generic-type construction, reflection-backed bean wiring — wherever a library chooses to fail fast on bad input instead of carrying it forward into a confusing later failure. Across the 658 records in this family it is rarely a bug in the library; it is almost always the caller handing it something its contract never agreed to accept.
Distilled from 658 documented records across 8 repositories.
Background
IllegalArgumentException lives in java.lang and extends RuntimeException, so it is unchecked: a library is not obliged to declare it, and the caller is not obliged to catch it. It exists for the case where a method's signature admits a value but the method's contract does not — the type checks, but the value, count, or structure is unacceptable. The records in this family show that Java libraries reach for it as a deliberate fail-fast guard. Elasticsearch throws it at configuration validation time before a node boots (prohibited telemetry keys, unknown secure-settings source); Spring Framework throws it during BeanFactory initialization before context refresh completes (missing targetField, a singleton bean declared with a per-object aspect clause); Gson throws it inside TypeToken.getParameterized before a malformed ParameterizedType is ever built; and the Painless scripting engine throws it at compile time rather than emitting broken bytecode for an unresolvable method or constructor reference. The shared instinct is identical: reject early, name the offending value, and stop.
From the caller's side the exception almost always carries the bad value in its message — the prohibited config key, the class name lacking a reflection-reachable constructor, the mismatched type-argument count, or the expected-versus-found SHA-256 digests of a patched JAR. Because it is unchecked, it surfaces wherever the library happens to be when validation runs: at application startup for configuration and bean wiring, at the first script execution for Painless, or mid-deserialization for a Jackson forward reference. There is no single predictable layer to catch it at; it fires at the boundary where the caller's input first crosses into the library's internals. Several records note a secondary, harder guard behind it — an assert enabled only with -ea, or a defensive duplicate throw that should be unreachable if validation and parsing stay in sync — so the IAE is usually the first and loudest line, not the only one. The trigger surface is library-specific, and the records disagree enough that no single rule covers all of them. Elasticsearch leans on hardcoded allowlists — permitted telemetry.agent keys, whitelisted Painless methods, constructors and functional interfaces, recognized secure-settings sources, supported date-object getters — so the dominant Elasticsearch shape is 'your value is not on the list.' Spring Framework uses IllegalArgumentException for structural contract checks during AOP and FactoryBean setup: an aspect must carry @Aspect, a per-object aspect must be prototype-scoped, and a custom service-locator exception must expose a (String, Throwable) constructor reflection can reach. Gson and Jackson use it to police generic and identity invariants — type-argument arity, owner-type requirements of non-static inner classes, unresolved forward references, and ambiguous Map-key creators. A smaller set of records uses it as a low-level precondition where a wrong argument would corrupt native state: a vector pitch that is smaller than the row length, or a Lucene Directory that is not filesystem-backed when the GPU codec needs a real file path. One exception family, four very different trigger surfaces.
Common causes
- Value not in a permitted set or allowlist.The most common shape. A library hardcodes the values it accepts and throws when the argument is not among them. Elasticsearch's Painless engine does this for method names, constructor arities, and functional interfaces; it also does it for telemetry.agent keys (PERMITTED_AGENT_KEYS), secure-settings sources, and the member methods of a date object. The fix is always to use a value that is on the published list, not to bypass the validator.
- Structural contract violation.The argument is an object that does not satisfy a structural requirement the library checks reflectively. Spring requires a service-locator exception class to expose a (String, Throwable) constructor, an aspect to carry @Aspect, and a per-object aspect to be prototype-scoped; Gson rejects non-static inner classes whose generic signature needs an owner type; Jackson rejects a Map-key type with more than one annotated single-String creator. The shared cause is a class shape the library never agreed to support.
- Arity or count mismatch.The number of arguments supplied does not equal the number declared. Gson's TypeToken.getParameterized throws when the type-argument count differs from rawClass.getTypeParameters().length; Painless throws when a function or constructor reference's arity does not match the functional interface's parameter count. The reported count sometimes excludes the receiver, which is a frequent source of off-by-one confusion.
- Malformed input string.The argument parses as a string but fails a grammar the library enforces. Gson rejects a custom Number subclass whose toString() is not RFC-8259-compliant; Elasticsearch rejects a version string matching none of its three compiled patterns; Spring Boot rejects CLI argument strings with unmatched quotes or dangling escapes that Maven's tokenizer rejects; and libzstd surfaces a corrupt mid-stream frame as an IllegalArgumentException carrying getErrorName(hint).
- Missing required configuration or property.A required key or property was not supplied at all. Elasticsearch's synonym filter needs exactly one of synonyms, synonyms_set, or synonyms_path; Spring's FieldRetrievingFactoryBean needs targetField once targetClass or targetObject is set. The library treats absence as an argument defect and fails at initialization rather than proceeding with a null.
- Configuration in the wrong location or under the wrong alias.The value is correct but placed where the parser does not accept it. Elasticsearch rejects project_routing inside the _msearch/template NDJSON body when it belongs in the URL query string, and rejects forbidden telemetry.agent.* keys that exist only under dedicated telemetry.* aliases. The argument is technically valid; its location is not.
- Version, digest, or module-boundary mismatch.An integrity or boundary guard rejects input that drifted from what it was authored against. Elasticsearch's JAR patcher throws when a targeted class's SHA-256 no longer matches the recorded digest; its MRJAR plugin rejects a src/mainNN directory whose version is below the build's minimum compiler version; and its module-wiring service rejects exports to a module not declared as a qualified recipient in module-info.java.
- Low-level data-layout precondition violated.A numeric or type argument breaks an invariant the native layer depends on. The vector dot-product kernel requires pitch to be at least the row length so rows do not overlap, and the GPU codec requires the Lucene Directory to unwrap to an FSDirectory so it can map a real file. These are pre-checks that prevent silent memory corruption rather than later logical errors.
What usually fixes it
- Read the exception message before changing anything. Across this family it names the offending value and the expectation — the prohibited key, the expected-versus-found digest, the required argument count. Several records append a hint about what was wrong; start there.
- Validate against the documented contract before the library does. Cross-check config keys against the published allowlist, match argument counts to getTypeParameters().length or the functional interface arity, and lint configuration in CI so the rejection happens at build time instead of in production.
- Put configuration where the library expects it. Use the dedicated alias rather than a forbidden namespace, place routing parameters in the URL query string where the parser reads them, and supply the one required source key the filter demands.
- Add the missing structural piece the contract requires. Give the exception class a public (String, Throwable) constructor, annotate the aspect with @Aspect and prototype scope, make the nested generic class static or supply an explicit owner type, and keep module-info.java qualified exports in sync with the modules you wire at runtime.
- Pin dependency versions and audit configuration on downgrade. JAR-patching digest guards, MRJAR source-version checks, and secure-settings source recognition all assume a specific upstream shape; a version bump or a downgrade to an older binary is the most common reason these guards start firing.
- Write a startup or CI test that fails fast on this family. Assert the exception class exposes a supported constructor, the aspect carries the right annotations and scope, the dynamically constructed TypeToken renders the expected generic signature, and a new analyzer or synonym filter is accepted by a dry-run before it reaches a production index.
Go deeper
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Documented occurrences
- Configuration [{qualifiedKey}] is either prohibited or unknown.(elastic/elasticsearch)
- Found src dir '${sourcesetName}' for Java ${version} but multi-release jar sourceset should have version ${minJavaVersion} or greater(elastic/elasticsearch)
- Pitch needs to be at least {}(elastic/elasticsearch)
- {} requires {} type arguments, but got {}(google/gson)
- Unknown key for a VALUE_STRING in [project_routing](elastic/elasticsearch)
- function reference [this::%s] matching [%s, %s/%d] not found%s(elastic/elasticsearch)
- Service locator exception [${exceptionClass.getName()}] neither has a (String, Throwable) constructor nor a (String) constructor(spring-projects/spring-framework)
- Unknown secure settings source [${source}](elastic/elasticsearch)
- Class name [{className}] is not a known auto-proxy creator class(spring-projects/spring-framework)
- Error patching JAR [%s]: SHA256 digest mismatch (%s). This JAR was updated to a version that contains different classes, for which this patcher was not designed. Please check if the patcher still applies correctly, and update the SHA256 digest(s).(elastic/elasticsearch)
- function reference [%s::new/%d] matching [%s, %s/%d] not found(elastic/elasticsearch)
- Trying to resolve a forward reference with id [${id}] that wasn't previously seen as unresolved.(FasterXML/jackson-databind)
- Module {module.getName()} does not contain qualified exports or opens for module {targetName}(elastic/elasticsearch)
- dynamic method [{}, {}/{}] not found(elastic/elasticsearch)
- synonym requires either `synonyms`, `synonyms_set` or `synonyms_path` to be configured(elastic/elasticsearch)
- Malformed jdk version [${version}](elastic/elasticsearch)
- Failed to parse arguments [{arguments}](spring-projects/spring-boot)
- String created by {} is not a valid JSON number: {}(google/gson)
- Raw type {} is not supported because it requires specifying an owner type(google/gson)
- targetField is required(spring-projects/spring-framework)
…and 638 more across the corpus — use search.
Honest provenance: generated on 2026-08-12 from AI-assisted analysis of the linked records. See how records are made.