hibernate/hibernate-orm · error · IllegalArgumentException
Unable to interpret LockMode reference from incoming externa
Error message
Unable to interpret LockMode reference from incoming external form: " + externalForm
What it means
LockMode.fromExternalForm(String) matches the incoming string case-insensitively against each LockMode's external form (the lowercased enum name, with underscores converted to hyphens for upgrade-nowait/upgrade-skiplocked) plus the legacy alias 'upgrade'. Any string that matches none of them - a typo, an old name, or free-form user input - throws IllegalArgumentException.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/LockMode.java:324
};
}
public static LockMode fromExternalForm(String externalForm) {
if ( externalForm == null ) {
return NONE;
}
for ( LockMode lockMode : values() ) {
if ( lockMode.toExternalForm().equalsIgnoreCase( externalForm ) ) {
return lockMode;
}
}
if ( externalForm.equalsIgnoreCase( "upgrade" ) ) {
return PESSIMISTIC_WRITE;
}
throw new IllegalArgumentException( "Unable to interpret LockMode reference from incoming external form: " + externalForm );
}
/**
* @return an instance of {@link LockOptions} with this lock mode, and
* all other settings defaulted.
*
* @deprecated With no replacement; {@linkplain LockOptions} is no longer considered an API.
*/
@Deprecated(since = "7", forRemoval = true)
public LockOptions toLockOptions() {
return switch (this) {
case NONE -> new LockOptions();
case READ -> new LockOptions( READ );
case OPTIMISTIC -> new LockOptions( OPTIMISTIC );
case OPTIMISTIC_FORCE_INCREMENT -> new LockOptions( OPTIMISTIC_FORCE_INCREMENT );
case UPGRADE_NOWAIT -> new LockOptions( PESSIMISTIC_WRITE, NO_WAIT_MILLI, PessimisticLockScope.NORMAL, Locking.FollowOn.ALLOW );
case UPGRADE_SKIPLOCKED -> new LockOptions( PESSIMISTIC_WRITE, SKIP_LOCKED_MILLI, PessimisticLockScope.NORMAL, Locking.FollowOn.ALLOW );
case PESSIMISTIC_READ -> new LockOptions( PESSIMISTIC_READ );View on GitHub (pinned to fad1729dce)
Solutions
- Use the exact external forms: none, read, write, optimistic, optimistic_force_increment, pessimistic_read, pessimistic_write, pessimistic_force_increment, upgrade-nowait, upgrade-skiplocked (legacy alias: upgrade).
- Prefer passing LockMode constants directly instead of strings when the value is in your control.
- Trim and normalize the string, and validate it against LockMode.values()/toExternalForm() before calling.
- Catch IllegalArgumentException and fall back to a safe default (e.g. LockMode.NONE) for external input.
Example fix
// before - underscore form never matches
LockMode mode = LockMode.fromExternalForm("UPGRADE_NOWAIT");
// after - valid external form (hyphenated, case-insensitive)
LockMode mode = LockMode.fromExternalForm("upgrade-nowait"); Defensive patterns
Strategy: validation
Validate before calling
static Optional<LockMode> tryParseLockMode(String raw) {
if (raw == null) return Optional.of(LockMode.NONE);
String s = raw.trim();
for (LockMode m : LockMode.values()) {
if (m.toExternalForm().equalsIgnoreCase(s)) return Optional.of(m);
}
if (s.equalsIgnoreCase("upgrade")) return Optional.of(LockMode.PESSIMISTIC_WRITE);
return Optional.empty();
}
Optional<LockMode> mode = tryParseLockMode(input);
LockMode lockMode = mode.orElseThrow(() -> new IllegalArgumentException("Unknown lock mode: " + input)); Type guard
static boolean isValidLockModeExternalForm(String raw) {
return tryParseLockMode(raw).isPresent();
} Try / catch
try {
LockMode mode = LockMode.fromExternalForm(input);
} catch (IllegalArgumentException e) {
log.warn("Ignoring unknown lock mode '{}', defaulting to NONE", input);
mode = LockMode.NONE; // never let free-form input crash request handling
} Prevention
- Validate external lock-mode strings against LockMode.toExternalForm() values before parsing
- Remember the hyphenated forms: upgrade-nowait, upgrade-skiplocked (not UPGRADE_NOWAIT)
- Trim input strings; pass LockMode constants instead of strings whenever possible
When it happens
Trigger: Calling LockMode.fromExternalForm("pessimistic write"), fromExternalForm("FORCE"), or fromExternalForm("UPGRADE_NOWAIT") (correct form is 'upgrade-nowait'). Typically the string comes from XML config, REST query parameters, or property files that name a lock mode.
Common situations: Parsing lock-mode strings from external configuration or user input; code migrating from Hibernate 5-era names (e.g. old 'FORCE' / underscore forms); whitespace or case variants slipping in ('READ ' with a trailing space).
Related errors
- WRITE is not a valid LockMode as an argument
- Lock mode ${lockMode} not valid for locking via 'update' sta
- Entity '{}' may not be locked at level {}
- Entity '{}' may not be locked at level {}
- Entity '{}' may not be locked at level {}
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/a4539a75b4e9b561.
Report an issue: GitHub.