{"record":{"id":"aa0fb70b401c6173","repo":"hibernate/hibernate-orm","slug":"literal-type-s-did-not-match-domain-type-s-n","errorCode":null,"errorMessage":"Literal type '%s' did not match domain type '%s' nor converted type '%s'","messagePattern":"Literal type '(.+?)' did not match domain type '(.+?)' nor converted type '(.+?)'","errorType":"exception","errorClass":"SemanticException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/sqm/sql/spi/BaseSqmToSqlAstConverter.java","lineNumber":6235,"sourceCode":"\t\t// For converted query literals, we support both, the domain and relational java type\n\t\tif ( value == null || valueConverter.getDomainJavaType().isInstance( value ) ) {\n\t\t\treturn toRelationalValue( valueConverter, value );\n\t\t}\n\t\telse if ( valueConverter.getRelationalJavaType().isInstance( value ) ) {\n\t\t\treturn value;\n\t\t}\n\t\telse if ( Character.class.isAssignableFrom( valueConverter.getRelationalJavaType().getJavaTypeClass() )\n\t\t\t\t&& value instanceof CharSequence charSequence && charSequence.length() == 1 ) {\n\t\t\treturn charSequence.charAt( 0 );\n\t\t}\n\t\t// In HQL, number literals might not match the relational java type exactly,\n\t\t// so we allow coercion between the number types\n\t\telse if ( Number.class.isAssignableFrom( valueConverter.getRelationalJavaType().getJavaTypeClass() )\n\t\t\t\t&& value instanceof Number ) {\n\t\t\treturn valueConverter.getRelationalJavaType().coerce( value );\n\t\t}\n\t\telse {\n\t\t\tthrow new SemanticException(\n\t\t\t\t\tString.format(\n\t\t\t\t\t\t\tLocale.ROOT,\n\t\t\t\t\t\t\t\"Literal type '%s' did not match domain type '%s' nor converted type '%s'\",\n\t\t\t\t\t\t\tvalue.getClass(),\n\t\t\t\t\t\t\tvalueConverter.getDomainJavaType().getJavaTypeClass().getName(),\n\t\t\t\t\t\t\tvalueConverter.getRelationalJavaType().getJavaTypeClass().getName()\n\t\t\t\t\t)\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate static <D> Object toRelationalValue(BasicValueConverter<D, ?> valueConverter, Object value) {\n\t\treturn valueConverter.toRelationalValue( valueConverter.getDomainJavaType().cast( value ) );\n\t}\n\n\tprivate <E> EntityTypeLiteral entityTypeLiteral(SqmLiteral<E> literal, DiscriminatorMapping inferableExpressible) {\n\t\tfinal E literalValue = literal.getLiteralValue();\n\t\tfinal var entityDescriptor =","sourceCodeStart":6217,"sourceCodeEnd":6253,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/spi/BaseSqmToSqlAstConverter.java#L6217-L6253","documentation":"While converting a literal to its relational value, the literal's Java class matched neither the domain Java type nor the relational Java type of the value converter in play. The converter only tolerates two special cases - a 1-char CharSequence against a Character relational type, and Number-to-Number coercion - so everything else is rejected as a SemanticException naming all three mismatched types.","triggerScenarios":"HQL like 'where e.converted = 123' where the attribute's AttributeConverter has domain type String (relational Integer) and the literal is written as the relational type; enum literals against converters with unusual domain types; comparing an attribute whose converter uses a boxed custom value type with a plain Java literal.","commonSituations":"Custom BasicConverter/AttributeConverter implementations with asymmetric domain/relational types (e.g. enum-to-code, String-to-int); writing query literals by looking at the DB column type instead of the Java attribute type; version upgrades that tightened literal coercion checks.","solutions":["Write the literal in the converter's domain type (the Java attribute type), not the column type","Replace the literal with a bound parameter: setParameter works through the converter and avoids literal conversion","Widen the converter's relational Java type to accept the literal form, or register a JavaType coercion","If the types truly match and it still throws, check for a broken JavaType.resolve/coerce override in a custom type"],"exampleFix":"// before: status stored as int via EnumConverter (domain Status, relational Integer)\nselect p from P p where p.status = 1\n\n// after: literal in domain type, or use a parameter\nselect p from P p where p.status = :st   // query.setParameter(\"st\", Status.ACTIVE)","handlingStrategy":"validation","validationCode":"// Before binding HQL literals for converted attributes: check the literal class against the domain type\nObject literal = ...;\nClass<?> domainType = sessionFactory.getMetamodel()\n    .entity(E.class).getAttribute(\"status\").getJavaType();\nif (!domainType.isInstance(literal)) {\n    throw new IllegalArgumentException(\"Literal \" + literal.getClass() + \" does not match domain type \" + domainType);\n}","typeGuard":null,"tryCatchPattern":"try {\n    return session.createQuery(hql).getResultList();\n} catch (org.hibernate.query.SemanticException e) {\n    log.error(\"Literal/converter mismatch in {}: {}\", hql, e.getMessage());\n    // switch the offending literal to a typed parameter and retry once\n    throw e;\n}","preventionTips":["Write literals in the Java attribute type, never the column type","Prefer parameters over literals for every converted attribute","Test each AttributeConverter with a query containing a literal of its domain type"],"tags":["hibernate","hql","literal","type-converter","type-mismatch"],"backgroundTag":"literal-converter-type-mismatch","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}