Fix java.lang.IllegalArgumentException: No enum constant When Converting String to Enum in Java

intermediateโ˜• Java2026-06-23| Java 8+, Spring Boot 2.x/3.x, JPA/Hibernate, Jackson โ€” any environment calling Enum.valueOf() or deserializing enums from JSON/database

Error Message

java.lang.IllegalArgumentException: No enum constant com.example.model.Status.UNKNOWN
#java#enum#conversion#illegalargumentexception#valueOf

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 is ACTIVE
  • 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.

Related Error Notes