prestodb/presto · error · SemanticException

TABLE_ALREADY_EXISTS

TABLE_ALREADY_EXISTS

Error message

Table '%s' already exists

What it means

CreateTableTask.internalExecute throws SemanticException(TABLE_ALREADY_EXISTS) when a table handle is already resolvable for the target qualified name and the statement did not include IF NOT EXISTS. The check happens against the metadata resolver before any connector-side table creation, so the error is raised before side effects.

Source

Thrown at presto-main-base/src/main/java/com/facebook/presto/execution/CreateTableTask.java:112

    }

    @Override
    public ListenableFuture<?> execute(CreateTable statement, TransactionManager transactionManager, Metadata metadata, AccessControl accessControl, Session session, List<Expression> parameters, WarningCollector warningCollector, String query)
    {
        return internalExecute(statement, metadata, accessControl, session, parameters, warningCollector, query);
    }

    @VisibleForTesting
    public ListenableFuture<?> internalExecute(CreateTable statement, Metadata metadata, AccessControl accessControl, Session session, List<Expression> parameters, WarningCollector warningCollector, String query)
    {
        checkArgument(!statement.getElements().isEmpty(), "no columns for table");

        Map<NodeRef<Parameter>, Expression> parameterLookup = parameterExtractor(statement, parameters);
        QualifiedObjectName tableName = createQualifiedObjectName(session, statement, statement.getName(), metadata);
        Optional<TableHandle> tableHandle = metadata.getMetadataResolver(session).getTableHandle(tableName);
        if (tableHandle.isPresent()) {
            if (!statement.isNotExists()) {
                throw new SemanticException(TABLE_ALREADY_EXISTS, statement, "Table '%s' already exists", tableName);
            }
            return immediateFuture(null);
        }

        ConnectorId connectorId = getConnectorIdOrThrow(session, metadata, tableName.getCatalogName());

        LinkedHashMap<String, ColumnMetadata> columns = new LinkedHashMap<>();
        Map<String, Object> inheritedProperties = ImmutableMap.of();
        boolean includingProperties = false;
        List<TableConstraint<String>> constraints = new ArrayList<>();
        for (TableElement element : statement.getElements()) {
            if (element instanceof ColumnDefinition) {
                ColumnDefinition column = (ColumnDefinition) element;
                String columnName = column.getName().getValue();
                String name = metadata.normalizeIdentifier(session, tableName.getCatalogName(), columnName);
                Type type;
                try {
                    type = metadata.getType(parseTypeSignature(column.getType()));

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Use CREATE TABLE IF NOT EXISTS to tolerate pre-existing tables.
  2. Check existence first (SHOW TABLES / metadata.getTableHandle) before issuing DDL.
  3. Drop the existing table explicitly if it is stale: DROP TABLE before re-creating.
  4. Have retry scripts treat TABLE_ALREADY_EXISTS as a no-op success.

Example fix

-- before
CREATE TABLE hive.default.events (id BIGINT); -- fails on rerun

-- after
CREATE TABLE IF NOT EXISTS hive.default.events (id BIGINT);
Defensive patterns

Strategy: try-catch

Validate before calling

QualifiedObjectName tableName = createQualifiedObjectName(session, statement, statement.getName(), metadata);
if (metadata.getMetadataResolver(session).getTableHandle(tableName).isPresent() && !statement.isNotExists()) {
    // skip creation or add IF NOT EXISTS
    return;
}

Type guard

boolean tableMissing(Session session, Metadata metadata, QualifiedObjectName tableName) {
    return metadata.getMetadataResolver(session).getTableHandle(tableName).isEmpty();
}

Try / catch

try {
    createTable(session, statement, parameters);
} catch (SemanticException e) {
    if (e.getCode() == TABLE_ALREADY_EXISTS) {
        // idempotent: verify schema matches, then continue
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: CREATE TABLE cat.schema.tbl ... where getTableHandle returns a handle and isNotExists() is false; re-running DDL scripts; concurrent pipelines racing to create the same table.

Common situations: Non-idempotent ETL bootstrap SQL; jobs retried after partial failure where the first attempt created the table; name collisions after identifier normalization.

Related errors


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/6800ec2d11da59ed. Report an issue: GitHub.