hibernate/hibernate-orm · error · SemanticException
Function [" + functionName.toLowerCase() + "] is not allowed
Error message
Function [" + functionName.toLowerCase() + "] is not allowed in safe mode
What it means
Thrown as SemanticException by SqmUtil.failIfSafeModeEnabled when safe mode is on and a disallowed function is used in HQL or Criteria. Safe mode (hibernate.query.safe_mode_enabled, QuerySettings.SAFE_MODE_ENABLED, default false, incubating since Hibernate 8.0) hardens queries against untrusted input: only explicitly registered/contributed functions are permitted, and escape hatches like the 'sql()' and 'column()' fragments in Criteria are blocked outright. The message lowercases the function name, e.g. 'Function [sql] is not allowed in safe mode'.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmUtil.java:1416
if ( !(parameter instanceof ValueBindJpaCriteriaParameter) ) {
parameterExpressions.add( parameter );
}
}
yield unmodifiableSet( parameterExpressions );
}
};
}
/**
* Throws a {@link SemanticException} if safe mode is enabled and the function is not allowed.
*
* @param safeModeEnabled whether safe mode is enabled
* @param functionName the name of the function to validate (will be converted to lowercase)
* @throws SemanticException if safe mode is enabled
*/
public static void failIfSafeModeEnabled(boolean safeModeEnabled, String functionName, @Nullable String queryString) {
if ( safeModeEnabled ) {
throw new SemanticException( "Function [" + functionName.toLowerCase() + "] is not allowed in safe mode", queryString );
}
}
}
View on GitHub (pinned to fad1729dce)
Solutions
- Contribute the function explicitly: implement org.hibernate.boot.model.FunctionContributor and register the function via FunctionContributions.getFunctionRegistry()
- Replace the blocked call with a registered dialect function or a normal HQL/Criteria expression
- If all queries are trusted, disable safe mode (remove hibernate.query.safe_mode_enabled=true)
- Keep user-supplied HQL in a separate SessionFactory configured with safe mode, and route internal trusted queries through a normal one
Example fix
// before: hibernate.query.safe_mode_enabled=true and HQL 'select reverse(p.name) from Person p' -> SemanticException
// after: contribute the function so safe mode accepts it
public class MyFunctionContributor implements FunctionContributor {
@Override
public void contributeFunctions(FunctionContributions contributions) {
contributions.getFunctionRegistry().registerPattern(
"reverse", "reverse(?1)",
contributions.getTypeConfiguration().getBasicTypeRegistry().resolve(String.class)
);
}
} Defensive patterns
Strategy: try-catch
Validate before calling
// before executing user-supplied HQL with safe mode on, screen the function names it may call
static final Set<String> ALLOWED = Set.of("lower", "upper", "length", "substring", "concat");
static boolean onlyAllowedFunctions(String hql) {
Matcher m = Pattern.compile("([A-Za-z_][A-Za-z0-9_]*)\\s*\\(").matcher(hql);
while (m.find()) {
if (!ALLOWED.contains(m.group(1).toLowerCase(Locale.ROOT))) return false;
}
return true;
} Try / catch
try {
return session.createSelectionQuery(userHql, Object[].class).getResultList();
} catch (SemanticException e) {
if (e.getMessage() != null && e.getMessage().contains("safe mode")) {
// unregistered function: reject the query, do not silently disable safe mode
throw new SecurityException("Query uses a function not allowed in safe mode", e);
}
throw e;
} Prevention
- Register every custom function via FunctionContributor so safe mode accepts it
- Never use cb.sql()/column() fragments in code paths where safe mode may be enabled
- Keep two SessionFactories: one hardened (safe mode) for user queries, one normal for internal queries
- Document the allowed function list for query authors
When it happens
Trigger: Setting hibernate.query.safe_mode_enabled=true (e.g. to accept HQL from users) and then executing queries that call unregistered functions; Criteria code using cb.function("sql", ...) or the sql()/column() escape APIs (SqmCriteriaNodeBuilder calls this check with name "sql" and "column"); custom dialect functions used in HQL that were never contributed through a FunctionContributor.
Common situations: Enabling safe mode for a query-builder/reporting feature that stores user-written HQL; upgrading to Hibernate 8 where the flag exists and ops turns it on globally; applications relying on ad-hoc SQL fragments inside criteria; multi-tenant products that must not let tenants call arbitrary DB functions.
Related errors
- Informix does not support binary literals
- Given subclass table number is outside expected range [%s] a
- Not implemented yet
- Result type of all operands must match
- Subquery parent of all operands must match
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/7482c4e3d24abc6a.
Report an issue: GitHub.