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

  1. Check existence before insert (or catch PrestoException ALREADY_EXISTS and treat as no-op).
  2. Delete/rename the existing type row if the new definition should replace it.
  3. Add idempotency to deployment scripts so duplicate registrations are skipped.
  4. 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

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.