{"record":{"id":"a75f90c51a087e6c","repo":"hibernate/hibernate-orm","slug":"invalid-temporal-field","errorCode":null,"errorMessage":"Invalid temporal field [{}]","messagePattern":"Invalid temporal field \\[(.+?)\\]","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java","lineNumber":3743,"sourceCode":"\t\t\t\ttemporalUnit = TemporalUnit.HOUR;\n\t\t\t\tbreak;\n\t\t\tcase \"minute\":\n\t\t\t\ttemporalUnit = TemporalUnit.MINUTE;\n\t\t\t\tbreak;\n\t\t\tcase \"second\":\n\t\t\t\ttemporalUnit = TemporalUnit.SECOND;\n\t\t\t\tresultType = Double.class;\n\t\t\t\tbreak;\n\t\t\tcase \"date\":\n\t\t\t\ttemporalUnit = TemporalUnit.DATE;\n\t\t\t\tresultType = LocalDate.class;\n\t\t\t\tbreak;\n\t\t\tcase \"time\":\n\t\t\t\ttemporalUnit = TemporalUnit.TIME;\n\t\t\t\tresultType = LocalTime.class;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tthrow new IllegalArgumentException( \"Invalid temporal field [\" + field + \"]\" );\n\t\t}\n\t\t//noinspection unchecked\n\t\treturn extract( temporal, temporalUnit, (Class<N>) resultType );\n\t}\n\n\tprivate <T> SqmFunction<T> extract(\n\t\t\tExpression<? extends TemporalAccessor> datetime,\n\t\t\tTemporalUnit temporalUnit,\n\t\t\tClass<T> type) {\n\t\treturn getFunctionDescriptor( \"extract\" ).generateSqmExpression(\n\t\t\t\tasList(\n\t\t\t\t\t\tnew SqmExtractUnit<>(\n\t\t\t\t\t\t\t\ttemporalUnit,\n\t\t\t\t\t\t\t\tgetTypeConfiguration().standardBasicTypeForJavaType( type ),\n\t\t\t\t\t\t\t\tthis\n\t\t\t\t\t\t),\n\t\t\t\t\t\t(SqmTypedNode<?>) datetime\n\t\t\t\t),","sourceCodeStart":3725,"sourceCodeEnd":3761,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java#L3725-L3761","documentation":"The criteria overload extract(TemporalField, Expression) maps the field to a TemporalUnit via a switch over field.toString(); only a fixed set of names is recognized (year, quarter, month, week, day, hour, minute, second, date, time per the surrounding switch). Any other string form — a custom enum constant, a typo, or fields Hibernate's switch doesn't cover — hits default and throws IllegalArgumentException.","triggerScenarios":"cb.extract(TemporalField.YEAR, ts) where TemporalField is a user-defined enum whose constant prints differently (e.g. 'Year' or 'YEAR_OF_ERA'); passing java.time.temporal.ChronoField constants not handled by the switch; typos in string-based field selection.","commonSituations":"Defining your own TemporalField-like enum for a query DSL and forwarding its constants; assuming every java.time.temporal.ChronoField is supported; upgrading Hibernate versions where the accepted-field switch changed.","solutions":["Use the unit-based overload: cb.extract(TemporalUnit.YEAR, ts) with org.hibernate.query.TemporalUnit, which has no string switch.","If you keep the TemporalField overload, make your enum's toString() return one of the recognized names exactly (lowercase: year, quarter, month, week, day, hour, minute, second, date, time).","Map your public API field names to the supported names before calling extract."],"exampleFix":"// before\nenum F { ISO_YEAR } // toString() = \"ISO_YEAR\"\ncb.extract(F.ISO_YEAR, ts); // Invalid temporal field [ISO_YEAR]\n\n// after\nimport org.hibernate.query.TemporalUnit;\ncb.extract(TemporalUnit.YEAR, ts);","handlingStrategy":"validation","validationCode":"private static final Set<String> SUPPORTED = Set.of(\n        \"year\", \"quarter\", \"month\", \"week\", \"day\",\n        \"hour\", \"minute\", \"second\", \"date\", \"time\");\n\nboolean supported(String field) { return SUPPORTED.contains(field.toLowerCase(Locale.ROOT)); }\nif (!supported(field.toString())) throw new IllegalArgumentException(\"Unsupported temporal field: \" + field);","typeGuard":"static boolean extractFieldSupported(TemporalField f) {\n    return Set.of(\"year\",\"quarter\",\"month\",\"week\",\"day\",\"hour\",\"minute\",\"second\",\"date\",\"time\")\n            .contains(f.toString());\n}","tryCatchPattern":"try {\n    e = cb.extract(field, ts);\n} catch (IllegalArgumentException ex) {\n    if (ex.getMessage().contains(\"Invalid temporal field\")) e = cb.extract(TemporalUnit.YEAR, ts);\n    else throw ex;\n}","preventionTips":["Prefer the TemporalUnit-based extract overload — no string switch involved.","If you own the TemporalField enum, make toString() return the exact lowercase names Hibernate recognizes.","Map external field names through a whitelist before calling extract."],"tags":["hibernate","criteria","extract","temporal","function-argument"],"backgroundTag":"invalid-temporal-field","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}