apache/beam · error · SqlUtil.newContextException
Function is already defined.
Error message
Function %s is already defined.
What it means
Thrown by CREATE FUNCTION when a function with the same name already exists in the target schema (schema.getFunctions(lastName) is non-empty). Beam does not allow redefinition of a UDF name within one schema, so it raises a parse-context internal error naming the function.
Solutions
- DROP FUNCTION fname first, then re-create it
- Use a different function name
- Guard DDL scripts to run only once or check function existence beforehand
Example fix
// before CREATE FUNCTION my_udf AS 'com.x.MyUdf' USING JAR 'gs://bucket/udf.jar'; // after DROP FUNCTION IF EXISTS my_udf; CREATE FUNCTION my_udf AS 'com.x.MyUdf' USING JAR 'gs://bucket/udf.jar';
Defensive patterns
Strategy: validation
Validate before calling
boolean fnExists = !schema.getFunctions("my_udf").isEmpty();
if (fnExists) { /* skip or drop first */ } Prevention
- Prefix DROP FUNCTION IF EXISTS before CREATE FUNCTION in scripts
- Avoid colliding with built-in Beam SQL function names
- Make UDF registration idempotent
When it happens
Trigger: `CREATE FUNCTION fname ...` where fname is already registered in the same schema — e.g. re-running a setup script or re-declaring a built-in/previous UDF name without dropping it first.
Common situations: Idempotent DDL scripts executed twice; name collision with a Beam built-in SQL function; re-registering a UDF after changing its jar without dropping the old one.
Understand the failure class
Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.
Related errors
- Jar path is not instanceof SqlCharStringLiteral.
- Attempting to alter catalog
- Attempting to create a table with unexpected Calcite Schema…
- Attempting to create catalog
- Attempting to create database
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/fa87f1289e7612f2.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/java/extensions/sql/src/main/java/org/apache/beam/sdk/extensions/sql/impl/parser/SqlCreateFunction.java:98
}
@Override
public SqlOperator getOperator() {
return OPERATOR;
}
@Override
public List<SqlNode> getOperandList() {
return Arrays.asList(functionName, jarPath);
}
@Override
public void execute(CalcitePrepare.Context context) {
final Pair<CalciteSchema, String> pair = SqlDdlNodes.schema(context, true, functionName);
SchemaPlus schema = pair.left.plus();
String lastName = pair.right;
if (!schema.getFunctions(lastName).isEmpty()) {
throw SqlUtil.newContextException(
functionName.getParserPosition(),
RESOURCE.internal(String.format("Function %s is already defined.", lastName)));
}
JavaUdfLoader udfLoader = new JavaUdfLoader();
// TODO(https://github.com/apache/beam/issues/20834) Support qualified function names.
List<String> functionPath = ImmutableList.of(lastName);
if (!(jarPath instanceof SqlCharStringLiteral)) {
throw SqlUtil.newContextException(
jarPath.getParserPosition(),
RESOURCE.internal("Jar path is not instanceof SqlCharStringLiteral."));
}
String unquotedJarPath = ((SqlCharStringLiteral) jarPath).getNlsString().getValue();
if (isAggregate) {
// Try loading the aggregate function just to make sure it exists. LazyAggregateCombineFn will
// need to fetch it again at runtime.
udfLoader.loadAggregateFunction(functionPath, unquotedJarPath);
LazyAggregateCombineFn<?, ?, ?> combineFn =
new LazyAggregateCombineFn<>(functionPath, unquotedJarPath);View on GitHub (pinned to 12126d8942)