TL;DR
You called SomeEnum.valueOf(string) with a value that doesn't exactly match any enum constant name โ usually a case mismatch, trailing whitespace, or a value your enum doesn't define yet. Skip the built-in valueOf() and add a case-insensitive lookup method to your enum instead.
// This throws if the string doesn't match exactly:
Status status = Status.valueOf(input);
// This handles case differences and unknown values gracefully:
Status status = Status.fromString(input);
Root Cause
Enum.valueOf() does a strict, case-sensitive name lookup. It's been this way since Java 1.5 โ by design, not a bug. The moment the string deviates, you get:
java.lang.IllegalArgumentException: No enum constant com.example.model.Status.UNKNOWN
Four inputs cause this 95% of the time:
- An external API sends
"active"(lowercase) but your constant isACTIVE - A database column stores
"Pending"or"pending"instead of"PENDING" - A third-party API added a new value before you added it to your Java model
- Form input that isn't normalized before conversion
Fix 1: Add a Case-Insensitive fromString() to Your Enum
Start here if you own the enum. A static fromString() method costs you 10 lines and eliminates the problem everywhere it's called โ no try-catch scattered across the codebase:
public enum Status {
ACTIVE, INACTIVE, PENDING;
public static Status fromString(String value) {
if (value == null) return null;
for (Status s : values()) {
if (s.name().equalsIgnoreCase(value.trim())) {
return s;
}
}
return null; // or throw a domain-specific exception here
}
}
Usage:
Status status = Status.fromString(input); // "active", "ACTIVE", " Active " all resolve correctly
if (status == null) {
throw new IllegalArgumentException("Unrecognized status: " + input);
}
Fix 2: Try-Catch Wrapper (Quick Patch)
No time to refactor the enum right now? Wrap valueOf() with a try-catch and normalize the string first:
public static Status parseStatus(String value) {
try {
return Status.valueOf(value.trim().toUpperCase());
} catch (IllegalArgumentException e) {
log.warn("Unknown status value received: {}", value);
return Status.PENDING; // safe fallback โ choose carefully
}
}
.trim().toUpperCase() knocks out the two most common causes in one shot. Pick your fallback value carefully, though. Silently defaulting to the wrong state can cause data corruption that's harder to debug than the original crash.
Fix 3: Jackson Deserialization with @JsonCreator
Getting this error inside a Spring Boot REST controller? The culprit is Jackson's default enum deserialization โ it calls valueOf() under the hood. Annotate a factory method with @JsonCreator to take over:
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
public enum Status {
ACTIVE, INACTIVE, PENDING;
@JsonCreator
public static Status fromJson(String value) {
if (value == null) return null;
try {
return Status.valueOf(value.toUpperCase().trim());
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("Invalid status: '" + value + "'");
}
}
@JsonValue
public String toJson() {
return name().toLowerCase();
}
}
A request body with {"status": "active"} now deserializes without throwing. The @JsonValue annotation keeps serialization consistent โ your API always writes lowercase back to the client.
Fix 4: JPA / Database Enum Mapping with AttributeConverter
Database columns are a frequent source of this error. When stored strings like "pending" or "Pending" don't match Java constant names, add an AttributeConverter to handle the translation in both directions:
import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Converter;
@Converter(autoApply = true)
public class StatusConverter implements AttributeConverter<Status, String> {
@Override
public String convertToDatabaseColumn(Status status) {
return status == null ? null : status.name().toLowerCase();
}
@Override
public Status convertToEntityAttribute(String dbData) {
return Status.fromString(dbData); // reuses the method from Fix 1
}
}
autoApply = true wires this converter to every Status field in your JPA entities automatically. No @Convert annotation needed on each field.
Fix 5: Apache Commons Lang EnumUtils
Already have Commons Lang in your dependencies? EnumUtils.getEnum() returns null on no match instead of throwing. One caveat: it's still case-sensitive, so pre-process the string if you need case-insensitive matching:
import org.apache.commons.lang3.EnumUtils;
Status status = EnumUtils.getEnum(Status.class, input.trim().toUpperCase());
if (status == null) {
// handle the unknown value
}
Maven dependency:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.14.0</version>
</dependency>
Verification
Don't skip the tests. Cover the exact inputs that crashed production โ lowercase, uppercase, mixed-case, leading/trailing whitespace, null, and unknown values:
@Test
void testFromString() {
assertEquals(Status.ACTIVE, Status.fromString("active"));
assertEquals(Status.ACTIVE, Status.fromString("ACTIVE"));
assertEquals(Status.ACTIVE, Status.fromString(" Active "));
assertNull(Status.fromString("UNKNOWN")); // unknown value returns null
assertNull(Status.fromString(null)); // null input handled safely
}
For JSON fixes, add a controller integration test. Send the exact payload that was failing and assert the response is 200, not 500.
Which Fix to Use
Pick based on where the string is coming from:
- General purpose enum in your own codebase โ Fix 1. Simple, testable, reusable everywhere.
- Spring Boot REST API receiving JSON โ Fix 3 (
@JsonCreator). Jackson picks it up automatically. - JPA entity backed by a string column โ Fix 4 (AttributeConverter). One converter handles all entity mappings.
- Hotfix under time pressure โ Fix 2 (try-catch). Better than nothing โ revisit it once the fire's out.

