{"record":{"id":"eb617cba066b800c","repo":"hibernate/hibernate-orm","slug":"no-changeset-exists-at-or-before-the-given-date","errorCode":null,"errorMessage":"No changeset exists at or before the given date","messagePattern":"No changeset exists at or before the given date","errorType":"exception","errorClass":"AuditException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/audit/internal/AuditLogImpl.java","lineNumber":403,"sourceCode":"\t\tfor ( var row : results ) {\n\t\t\tmap.put( row[0], changelogClass.cast( row[1] ) );\n\t\t}\n\t\treturn map;\n\t}\n\n\t// --- Helpers ---\n\n\tprivate Object resolveChangesetIdForTimestamp(Object timestampValue) {\n\t\trequireChangelog();\n\t\tfinal String hql = \"select max(e.\" + changesetIdProperty + \")\"\n\t\t\t\t+ \" from \" + changelogName + \" e\"\n\t\t\t\t+ \" where e.\" + timestampProperty + \" <= :ts\";\n\t\tfinal var result = auditSession\n\t\t\t\t.createSelectionQuery( hql, Object.class )\n\t\t\t\t.setParameter( \"ts\", timestampValue )\n\t\t\t\t.getSingleResultOrNull();\n\t\tif ( result == null ) {\n\t\t\tthrow new AuditException( \"No changeset exists at or before the given date\" );\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Convert an {@link Instant} to match the changelog entity's\n\t * timestamp field type.\n\t */\n\tprivate Object resolveTimestampValue(Instant instant) {\n\t\tif ( timestampFieldType == Date.class ) {\n\t\t\treturn Date.from( instant );\n\t\t}\n\t\telse if ( timestampFieldType == LocalDateTime.class ) {\n\t\t\treturn LocalDateTime.ofInstant( instant, ZoneId.systemDefault() );\n\t\t}\n\t\telse if ( timestampFieldType == Instant.class ) {\n\t\t\treturn instant;\n\t\t}","sourceCodeStart":385,"sourceCodeEnd":421,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/audit/internal/AuditLogImpl.java#L385-L421","documentation":"AuditLog.getChangesetId(Instant) resolves the changeset in effect at a timestamp via select max(changesetId) where changelog.timestamp <= :ts. If no changeset was committed at or before that instant - or the changelog table is empty - the aggregate returns null and AuditException('No changeset exists at or before the given date') is thrown.","triggerScenarios":"Querying at an instant earlier than the first changeset; querying an empty audit schema; timezone/precision skew (LocalDateTime changelog fields are interpreted with ZoneId.systemDefault()) turning an 'after' instant into 'before'.","commonSituations":"Boundary queries at application startup before any audit data exists; tests against fresh databases; application servers in a different timezone than the writer.","solutions":["Query at an instant at/after the first changeset - find it first with 'select min(r.<timestampProperty>) from <ChangelogEntity> r'.","If the audit schema is empty, skip the temporal lookup entirely.","Check timezone handling: align changelog timestamp storage (Date/LocalDateTime/epoch millis) with the query instant's zone."],"exampleFix":"// before - before the first changeset\nObject csId = auditLog.getChangesetId(Instant.parse(\"2020-01-01T00:00:00Z\")); // throws\n// after - use an instant at/after the first changeset\nObject csId = auditLog.getChangesetId(firstChangesetInstant.plusNanos(1));","handlingStrategy":"validation","validationCode":"// guard: only ask for a changeset when one exists at/before the instant\nboolean any = !em.createQuery(\"select 1 from RevEntity r where r.at <= :t\", Integer.class)\n    .setParameter(\"t\", Date.from(instant))\n    .setMaxResults(1)\n    .getResultList().isEmpty();\nObject csId = any ? auditLog.getChangesetId(instant) : null;","typeGuard":null,"tryCatchPattern":"try {\n    csId = auditLog.getChangesetId(instant);\n}\ncatch (AuditException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"No changeset exists at or before\")) {\n        csId = null; // nothing was audited yet at that point in time\n    }\n    else throw e;\n}","preventionTips":["Seed or check the first changeset timestamp before issuing historical point-in-time lookups","Keep writers and readers on consistent timezone settings; LocalDateTime fields use the system zone","Skip temporal queries against fresh or empty audit schemas"],"tags":["hibernate","audit","changeset","temporal-query","not-found"],"backgroundTag":"changeset-not-found","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}