prestodb/presto · error · SemanticException

MATERIALIZED_VIEW_ALREADY_EXISTS

MATERIALIZED_VIEW_ALREADY_EXISTS

Error message

Destination materialized view '%s' already exists

What it means

CREATE MATERIALIZED VIEW fails when the destination materialized view (or table) name already exists, unless IF NOT EXISTS is specified. visitCreateMaterializedView checks metadataResolver.tableExists(viewName) and throws MATERIALIZED_VIEW_ALREADY_EXISTS when isNotExists() is false.

Source

Thrown at presto-main-base/src/main/java/com/facebook/presto/sql/analyzer/StatementAnalyzer.java:895

            accessControl.checkCanCreateView(session.getRequiredTransactionId(), session.getIdentity(), session.getAccessControlContext(), viewName);

            validateColumns(node, queryScope.getRelationType());

            return createAndAssignScope(node, scope);
        }

        @Override
        protected Scope visitCreateMaterializedView(CreateMaterializedView node, Optional<Scope> scope)
        {
            QualifiedObjectName viewName = createQualifiedObjectName(session, node, node.getName(), metadata);
            analysis.setUpdateInfo(node.getUpdateInfo());
            analysis.setCreateTableDestination(viewName);

            if (metadataResolver.tableExists(viewName)) {
                if (node.isNotExists()) {
                    return createAndAssignScope(node, scope);
                }
                throw new SemanticException(MATERIALIZED_VIEW_ALREADY_EXISTS, node, "Destination materialized view '%s' already exists", viewName);
            }
            validateProperties(node.getProperties(), scope);

            analysis.setCreateTableProperties(mapFromProperties(node.getProperties()));
            analysis.setCreateTableComment(node.getComment());

            accessControl.checkCanCreateTable(session.getRequiredTransactionId(), session.getIdentity(), session.getAccessControlContext(), viewName);
            accessControl.checkCanCreateView(session.getRequiredTransactionId(), session.getIdentity(), session.getAccessControlContext(), viewName);

            // analyze the query that creates the table
            Scope queryScope = process(node.getQuery(), scope);

            validateColumns(node, queryScope.getRelationType());

            validateBaseTables(analysis.getTableNodes(), node);

            validateDeterministicFunctionsInMV(node);

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Add IF NOT EXISTS: CREATE MATERIALIZED VIEW IF NOT EXISTS ...
  2. DROP MATERIALIZED VIEW (or TABLE) with the conflicting name first, then recreate
  3. Use a new destination name for the materialized view

Example fix

-- before
CREATE MATERIALIZED VIEW reports.summary AS SELECT ...;
-- after
CREATE MATERIALIZED VIEW IF NOT EXISTS reports.summary AS SELECT ...;
Defensive patterns

Strategy: try-catch

Validate before calling

// before CREATE MATERIALIZED VIEW:
// boolean exists = metadataResolver.tableExists(viewName);

Try / catch

catch (SemanticException e) { if (e.getCode() == MATERIALIZED_VIEW_ALREADY_EXISTS) { /* use IF NOT EXISTS or drop first */ } }

Prevention

When it happens

Trigger: CREATE MATERIALIZED VIEW on an existing name without IF NOT EXISTS; note the guard uses tableExists so an ordinary table with that name also triggers it.

Common situations: Re-deploying materialized view definitions from version control without drop-first; a name collision with an existing table; re-running setup scripts.

Related errors


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