🔴 The Error You're Seeing
Confirm this matches your console output. If it does, you're in the right place.
Exception in thread "main" java.lang.IllegalArgumentException: No enum constant com.devinhyderabad.pay.Status.COMPLTED
at java.base/java.lang.Enum.valueOf(Enum.java:273)
at com.devinhyderabad.pay.Status.valueOf(Status.java:3)
at com.devinhyderabad.pay.StatusMain.main(StatusMain.java:5)
// Second famous tenant — TimSort legality check (DOC-DERIVED canonical):
Exception in thread "main" java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.base/java.util.TimSort.mergeHi(TimSort.java:<v>)
at java.base/java.util.TimSort.mergeAt(TimSort.java:<v>)
at java.base/java.util.Arrays.sort(Arrays.java:<v>)
at com.devinhyderabad.reports.Leaderboard.rank(Leaderboard.java:20)⚡ Quick Fix Works 80% of the time
Never feed unvetted strings into valueOf — wrap lookups in a safe helper returning Optional or a default.
public static <E extends Enum<E>> Optional<E> lookup(
Class<E> type, String raw) {
if (raw == null) return Optional.empty();
try {
return Optional.of(Enum.valueOf(type, raw.trim()));
} catch (IllegalArgumentException e) {
return Optional.empty();
}
}🧠 Why this Happens
Tap to expand the deep technical explanation
The compiler generates Status.valueOf as a thin delegate to Enum.valueOf, which hashes the requested name against the $VALUES directory built reflectively during enum class initialization. A miss produces the concatenated diagnostic "No enum constant <class>.<name>". The TimSort side is defensive engineering: since JDK 7, merge routines verify run invariants as they combine sorted runs, and contradictory comparisons prove the Comparator broke transitivity/sign-consistency — throwing beats silently returning wrongly-sorted data, which is exactly what pre-7 merge sort did.
The HITEC City Parking Spot Analogy:
Enum lookup is a hotel front desk matching guests by EXACT spelling: COMPLTED is not on the list no matter how close it looks to COMPLETED. TimSort is a referee who stops the whole tournament the moment two judges submit contradictory rankings.
🔁 How to Reproduce Confirm this is your error
Define enum Status { ACTIVE, PAUSED } and call Status.valueOf("COMPLTED") — instant throw captured verbatim on OpenJDK 17 (Enum.java line reads 293 on JDK 25). The TimSort block needs a contract-violating Comparator over a large list; deterministic repro is fiddly, so that block stays documentation-canonical.
🛠️ Solutions (5 Ways to Fix)
Safe enum lookup: Optional/default instead of valueOf crash
👉 Use this whenever enum values cross a boundary — DB columns, wire payloads, CSV cells, query params.
Stored values drift from enum names constantly: typos like COMPLTED, casing changes, renamed constants after deploy. Centralize tolerant lookup once; normalize case if your domain allows, and choose an explicit fallback instead of letting a typo kill a request.
Status s = lookup(Status.class, dbValue)
.orElseThrow(() -> new IllegalStateException(
"unknown status stored: [" + dbValue + "]"));
// Or tolerate-and-default where business rules allow:
Status lenient = lookup(Status.class, dbValue).orElse(Status.ACTIVE);Fix comparator overflow — the #1 TimSort killer
👉 Use this when the trace shows Comparison method violates its general contract!.
(a, b) -> a.score - b.score breaks when subtraction overflows int (2_000_000_000 minus -2_000_000_000 wraps negative), flipping comparison signs mid-sort. TimSort detects the inconsistency across merge runs and throws rather than emit corrupt orderings. Always Comparator.comparingX — never hand-subtracted keys.
// BROKEN: overflow flips signs on extreme scores
items.sort((a, b) -> a.score() - b.score());
// FIXED:
items.sort(Comparator.comparingInt(Item::score));
// Doubles: Double.compare(a.weight(), b.weight())Throw IAE yourself — early and descriptively
👉 Use this when writing API entry points that receive caller-supplied values.
IllegalArgumentException is the CORRECT tool for caller mistakes: validate at method entry with a message naming the parameter and the offending value. A clear IAE at the boundary beats a deep mysterious failure three layers later.
public void schedule(Job job, int retries) {
if (retries < 0 || retries > 10) {
throw new IllegalArgumentException(
"retries must be 0..10, got " + retries);
}
...
}Map the subclass family your catches inherit
👉 Use this to reason about what catch (IllegalArgumentException) really captures.
NumberFormatException and IllegalThreadStateException both EXTEND IAE — catching IAE nets parse failures and thread-state misuse too. Useful for broad guards at edges; harmful mid-stack when you meant to isolate only parsing. The hierarchy runs: RuntimeException -> IllegalArgumentException -> {NumberFormatException, IllegalThreadStateException}.
catch (IllegalArgumentException e) {
// also lands here:
// NumberFormatException ("For input string: ...")
// IllegalThreadStateException (start() twice, etc.)
}Standardize range checks with Objects.check* helpers
👉 Use this for index/range contracts instead of hand-written if-throw chains.
Objects.checkIndex/checkFromToIndex (Java 9+) produce descriptive IndexOutOfBoundsException wording consistently and document intent. Same fail-fast philosophy as IAE with standard library backing.
int safeFrom = Objects.checkIndex(from, items.size());
int safeTo = Objects.checkFromToIndex(from, to, items.size());
return items.subList(safeFrom, safeTo);📋 Version Notes
Both famous messages already present ("No enum constant", TimSort contract); Enum.valueOf frame lacks module prefix.
java.base/-prefixed frames appear; Objects.checkIndex family added to java.util.Objects.
Captured wording byte-identical vs JDK 25; internal Enum.valueOf line numbers drift between builds (273@17, 293@25).
Unchanged; pattern-matching switch adds new ways to AVOID valueOf crashes, not new messages.
🛡️ How to Prevent This Next Time
Funnel all external values through centralized tolerant lookups, ban manual subtraction comparators via review/lint, validate parameters at entry with parameter-naming messages, and unit-test enums against every legacy stored value.