prestodb/presto · error · PrestoException
ALREADY_EXISTS
ALREADY_EXISTS
Error message
Type %s already exists
What it means
MySqlFunctionNamespaceManager.addUserDefinedType inserts a UDT row into the MySQL-backed namespace. Within the insert transaction it first checks typeExists; if a row for the same catalog/schema/object name is present, it throws ALREADY_EXISTS to enforce unique type names.
Source
Thrown at presto-function-namespace-managers/src/main/java/com/facebook/presto/functionNamespace/mysql/MySqlFunctionNamespaceManager.java:110
functionNamespaceDao.createFunctionNamespacesTableIfNotExists();
functionNamespaceDao.createSqlFunctionsTableIfNotExists();
functionNamespaceDao.createUserDefinedTypesTableIfNotExists();
}
@Override
public Collection<SqlInvokedFunction> listFunctions(Optional<String> likePattern, Optional<String> escape)
{
return likePattern.map(pattern -> functionNamespaceDao.listFunctions(getCatalogName(), pattern, escape.orElse("\\"))).orElse(functionNamespaceDao.listFunctions(getCatalogName()));
}
@Override
public void addUserDefinedType(UserDefinedType type)
{
jdbi.useTransaction(handle -> {
FunctionNamespaceDao transactionDao = handle.attach(functionNamespaceDaoClass);
QualifiedObjectName typeName = type.getUserDefinedTypeName();
if (functionNamespaceDao.typeExists(typeName.getCatalogName(), typeName.getSchemaName(), typeName.getObjectName())) {
throw new PrestoException(ALREADY_EXISTS, format("Type %s already exists", typeName));
}
transactionDao.insertUserDefinedType(typeName.getCatalogName(), typeName.getSchemaName(), typeName.getObjectName(), type.getPhysicalTypeSignature().toString());
});
}
@Override
public UserDefinedType fetchUserDefinedTypeDirect(QualifiedObjectName typeName)
{
Optional<UserDefinedType> type = functionNamespaceDao.getUserDefinedType(typeName.getCatalogName(), typeName.getSchemaName(), typeName.getObjectName());
return type.orElseThrow(() -> new PrestoException(NOT_FOUND, format("Type %s not found", typeName)));
}
@Override
protected Collection<SqlInvokedFunction> fetchFunctionsDirect(QualifiedObjectName functionName)
{
checkCatalog(functionName);
return functionNamespaceDao.getFunctions(
functionName.getCatalogName(),View on GitHub (pinned to 55bb57d202)
Solutions
- Check existence before insert (or catch PrestoException ALREADY_EXISTS and treat as no-op).
- Delete/rename the existing type row if the new definition should replace it.
- Add idempotency to deployment scripts so duplicate registrations are skipped.
- Serialize UDT registration across workers (lock or leader election) to avoid races.
Example fix
// before
dao.insertUserDefinedType(catalog, schema, object, signature);
// after
if (!dao.typeExists(catalog, schema, object)) {
dao.insertUserDefinedType(catalog, schema, object, signature);
} Defensive patterns
Strategy: try-catch
Validate before calling
if (functionNamespaceDao.typeExists(typeName.getCatalogName(), typeName.getSchemaName(), typeName.getObjectName())) {
return; // already registered, skip
} Try / catch
try {
manager.addUserDefinedType(type);
} catch (PrestoException e) {
if (!isAlreadyExists(e)) { throw e; } // treat duplicate as success
} Prevention
- Make UDT registration idempotent
- Serialize registration across workers
- Verify existing types before insert
When it happens
Trigger: Calling addUserDefinedType(type) when functionNamespaceDao.typeExists already returns true for the type's qualified name (catalog, schema, object).
Common situations: Replaying UDT registration scripts; two workers racing to register the same type; re-registering types after a partial failed deployment left rows behind.
Related errors
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/ebc41231ba288a1b.
Report an issue: GitHub.