prestodb/presto · error · PrestoException
NOT_SUPPORTED
NOT_SUPPORTED
Error message
Invoking a dynamically registered function in SQL function body is not supported
What it means
CREATE FUNCTION bodies may only call functions resolvable at creation time. If semantic analysis of the function body yields handles that are instances of SqlFunctionHandle — i.e. dynamically (session-level) registered SQL functions — CreateFunctionTask throws PrestoException NOT_SUPPORTED.
Source
Thrown at presto-main-base/src/main/java/com/facebook/presto/execution/CreateFunctionTask.java:98
@Override
public String explain(CreateFunction statement, List<Expression> parameters)
{
return format("CREATE %sFUNCTION %s", statement.isTemporary() ? "TEMPORARY " : "", statement.getFunctionName());
}
@Override
public ListenableFuture<?> execute(CreateFunction statement, TransactionManager transactionManager, Metadata metadata, AccessControl accessControl, QueryStateMachine stateMachine, List<Expression> parameters, String query)
{
Map<NodeRef<com.facebook.presto.sql.tree.Parameter>, Expression> parameterLookup = parameterExtractor(statement, parameters);
Session session = stateMachine.getSession();
Analyzer analyzer = new Analyzer(session, metadata, sqlParser, accessControl, Optional.empty(), parameters, parameterLookup, stateMachine.getWarningCollector(), query, new ViewDefinitionReferences());
Analysis analysis = analyzer.analyzeSemantic(statement, false);
checkAccessPermissions(analysis.getAccessControlReferences(), analysis.getViewDefinitionReferences(), query, session.getPreparedStatements(), session.getIdentity(), accessControl, session.getAccessControlContext());
if (analysis.getFunctionHandles().values().stream()
.anyMatch(SqlFunctionHandle.class::isInstance)) {
throw new PrestoException(NOT_SUPPORTED, "Invoking a dynamically registered function in SQL function body is not supported");
}
SqlInvokedFunction function = createSqlInvokedFunction(statement, metadata, analysis);
if (statement.isTemporary()) {
stateMachine.addSessionFunction(new SqlFunctionId(function.getSignature().getName(), function.getSignature().getArgumentTypes()), function);
}
else {
metadata.getFunctionAndTypeManager().createFunction(function, statement.isReplace());
}
return immediateFuture(null);
}
@Override
public void queryPermissionCheck(AccessControl accessControl, Identity identity, AccessControlContext context, String query, Map<String, String> preparedStatements, Map<QualifiedObjectName, ViewDefinition> viewDefinitions, Map<QualifiedObjectName, MaterializedViewDefinition> materializedViewDefinitions) {}
private SqlInvokedFunction createSqlInvokedFunction(CreateFunction statement, Metadata metadata, Analysis analysis)
{View on GitHub (pinned to 55bb57d202)
Solutions
- Remove the call to the dynamically registered function from the function body
- Register the dependency as a persistent catalog function so the body resolves a static handle
- Inline the dependent function's logic into the new function body
- Restructure to define the dependency first as a permanent function in the same catalog
Example fix
// before CREATE FUNCTION my.lib.f(x bigint) RETURNS bigint AS $$ SELECT my.session_helper(x) + 1 $$; -- session_helper is dynamic // after CREATE FUNCTION my.lib.helper(x bigint) RETURNS bigint AS $$ ... $$; -- permanent CREATE FUNCTION my.lib.f(x bigint) RETURNS bigint AS $$ SELECT my.lib.helper(x) + 1 $$;
Defensive patterns
Strategy: validation
Validate before calling
// ensure function bodies only reference persistent functions
Set<String> dynamicFunctions = sessionFunctions.keySet();
for (String callee : referencedFunctions(body)) {
if (dynamicFunctions.contains(callee)) {
throw new IllegalStateException("Body references dynamic function: " + callee);
}
} Prevention
- Register helper functions as persistent catalog functions, not session-temporary
- Never build permanent functions on top of session-scoped temporary functions
- Review function definition scripts for cross-session dependencies
When it happens
Trigger: Defining a SQL function whose body calls a function registered dynamically in the session (e.g. via a prior temporary CREATE FUNCTION in the same session); nesting dynamic function references inside new function definitions.
Common situations: Scripted sessions that register helper functions and then build more functions on top; session-scoped temporary functions referenced from persistent catalog functions; migration scripts chaining function definitions.
Understand the failure class
Background: Presto NOT_SUPPORTED error: what "not supported" means and how to fix it — this error's family across 3 libraries.
Related errors
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/403bb73132c1a3d2.
Report an issue: GitHub.