hibernate/hibernate-orm · error · MappingException
unsaved-value NEGATIVE may only be used with short, int and
Error message
unsaved-value NEGATIVE may only be used with short, int and long types
What it means
VersionValue.NEGATIVE implements the legacy 'unsaved-value=negative' strategy: an entity is considered unsaved when its version is a negative number. isUnsaved() only handles null (unsaved) and Number values; any other non-null version object proves the strategy was configured for an unsupported attribute type, so a MappingException is thrown. The in-code FIXME notes modern mapping cannot even select NEGATIVE anymore, so hitting this means legacy or hand-built configuration.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/engine/spi/VersionValue.java:85
}
};
/**
* Assume the transient instance is newly instantiated if the version
* is negative, otherwise assume it is a detached instance.
*/
public static final VersionValue NEGATIVE = new VersionValue() {
@Override
public Boolean isUnsaved(@Nullable Object version) throws MappingException {
CORE_LOGGER.versionUnsavedValueStrategy( "NEGATIVE" );
if ( version == null ) {
return Boolean.TRUE;
}
if ( version instanceof Number number ) {
return number.longValue() < 0L;
}
throw new MappingException( "unsaved-value NEGATIVE may only be used with short, int and long types" );
}
@Override
public Object getDefaultValue(@Nullable Object currentValue) {
// FIXME this does not handle null values, and it's unknown how they should be handled.
// Probably worse, org.hibernate.mapping.SimpleValue.decodeNullValueSemantic is the only
// place where we define null value semantics, and it can never select "negatic" semantics,
// which means this implementation of VersionValue is likely not tested and even dead code.
return IdentifierGeneratorHelper.makeIntegralValue( -1L, castNonNull( currentValue ).getClass() );
}
@Override
public String toString() {
return "VERSION_NEGATIVE";
}
};
protected VersionValue() {View on GitHub (pinned to fad1729dce)
Solutions
- Remove unsaved-value="negative" and rely on the modern default (undefined/null semantics with a version column)
- If negative-version semantics are truly required, make the version property a short, int, or long
- For timestamp versions, let Hibernate decide unsaved state via the version null check instead of the negative trick
Example fix
// before (hbm.xml legacy mapping) <version name="version" column="ver" type="timestamp" unsaved-value="negative"/> // after <version name="version" column="ver" type="integer"/> <!-- or drop unsaved-value and keep default -->
Defensive patterns
Strategy: validation
Validate before calling
Class<?> versionClass = versionValue.getClass();
if (!(versionClass == Short.class || versionClass == Integer.class || versionClass == Long.class)) {
throw new MappingException("unsaved-value=negative requires short/int/long version, got " + versionClass.getName());
} Type guard
static boolean supportsNegativeUnsavedValue(Object version) {
return version == null
|| version instanceof Short || version instanceof Integer || version instanceof Long;
} Prevention
- Prefer modern unsaved-value semantics (undefined/null) over 'negative'
- Reserve unsaved-value=negative for numeric version columns only
- Run mapping tests at boot for legacy hbm.xml migrations
When it happens
Trigger: unsaved-value="negative" on a version property whose type is not numeric — e.g. a Timestamp/Date, String, or user type version — so isUnsaved() receives a non-null, non-Number object at flush/load time.
Common situations: Porting Hibernate 2/3-era mappings where unsaved-value=negative was used with timestamp optimistic-lock values; hand-constructing VersionValue.NEGATIVE; old hbm.xml files copied into a modern project.
Related errors
- Entity '{name}' has 'OptimisticLockType.{optimisticLockStyle
- The INSERT statement for table [%s] contains no column, and
- cannot recreate collection while filter is enabled: " + coll
- Newer version [" + latestVersion + "] of entity [" + infoStr
- cannot recreate collection while filter is enabled [%s : %s]
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/98fbd5c56f29ac66.
Report an issue: GitHub.