hibernate/hibernate-orm · error · AuditException

Cannot convert changeset timestamp to Instant: <value>

Error message

Cannot convert changeset timestamp to Instant: <value>

What it means

AuditLog converts changelog timestamp values to java.time.Instant with a fixed chain: Instant as-is, LocalDateTime via the system zone, java.util.Date via toInstant(), Long as epoch millis. Any other runtime type - LocalDate, OffsetDateTime, java.sql.Timestamp, or a custom user type - falls through the chain and AuditException('Cannot convert changeset timestamp to Instant: <value>') is thrown.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/audit/internal/AuditLogImpl.java:467

			);
		}
		return persister.getEntityName();
	}

	private static Instant toInstant(Object value) {
		if ( value instanceof Instant instant ) {
			return instant;
		}
		else if ( value instanceof LocalDateTime localDateTime ) {
			return localDateTime.atZone( ZoneId.systemDefault() ).toInstant();
		}
		else if ( value instanceof Date date ) {
			return date.toInstant();
		}
		else if ( value instanceof Long millis ) {
			return Instant.ofEpochMilli( millis );
		}
		throw new AuditException( "Cannot convert changeset timestamp to Instant: " + value );
	}
}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Change the changelog timestamp property to Instant, LocalDateTime, java.util.Date, or Long (epoch millis).
  2. If the exotic type must stay, query the changelog entity yourself and convert the value in application code.

Example fix

// before
@Changelog.Timestamp
LocalDate changeDate; // unsupported by AuditLog conversion
// after
@Changelog.Timestamp
Instant changedAt;
Defensive patterns

Strategy: validation

Validate before calling

// fail fast at bootstrap when the changelog timestamp type is unsupported
Field f = RevEntity.class.getDeclaredField("changedAt");
Class<?> t = f.getType();
if (!(t == Instant.class || t == LocalDateTime.class || t == Date.class || t == Long.class)) {
    throw new IllegalStateException("Unsupported @Changelog.Timestamp type: " + t);
}

Type guard

static boolean supportedTimestampType(Class<?> t) {
    return t == Instant.class || t == LocalDateTime.class
        || t == Date.class || t == Long.class || t == long.class;
}

Prevention

When it happens

Trigger: Declaring the @Changelog.Timestamp property with a type outside the supported set (e.g. LocalDate or a converted custom type) and then calling a timestamp-returning API such as getChangesetTimestamp.

Common situations: Date-only changelog fields modeled as LocalDate; joda-style or custom AttributeConverter types; java.sql.Timestamp fields on legacy changelog entities.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/48af788a6264c97c. Report an issue: GitHub.