prestodb/presto · error · SemanticException
MATERIALIZED_VIEW_ALREADY_EXISTS
MATERIALIZED_VIEW_ALREADY_EXISTS
Error message
Materialized view '%s' already exists
What it means
CREATE MATERIALIZED VIEW found an existing table handle at the target name and the statement did not include IF NOT EXISTS, so the materialized view already exists. The task throws SemanticException MATERIALIZED_VIEW_ALREADY_EXISTS to prevent silent replacement.
Source
Thrown at presto-main-base/src/main/java/com/facebook/presto/execution/CreateMaterializedViewTask.java:109
@Override
public ListenableFuture<?> execute(CreateMaterializedView statement, TransactionManager transactionManager, Metadata metadata, AccessControl accessControl, Session session, List<Expression> parameters, WarningCollector warningCollector, String query)
{
QualifiedObjectName viewName = createQualifiedObjectName(session, statement, statement.getName(), metadata);
MetadataResolver metadataResolver = metadata.getMetadataResolver(session);
if (!metadataResolver.catalogExists(viewName.getCatalogName())) {
throw new SemanticException(MISSING_CATALOG, "Catalog '%s' does not exist", viewName.getCatalogName());
}
if (!metadataResolver.schemaExists(viewName.getCatalogSchemaName())) {
throw new SemanticException(MISSING_SCHEMA, statement, "Schema '%s' does not exist", viewName.getSchemaName());
}
Optional<TableHandle> viewHandle = metadataResolver.getTableHandle(viewName);
if (viewHandle.isPresent()) {
if (!statement.isNotExists()) {
throw new SemanticException(MATERIALIZED_VIEW_ALREADY_EXISTS, statement, "Materialized view '%s' already exists", viewName);
}
return immediateFuture(null);
}
accessControl.checkCanCreateTable(session.getRequiredTransactionId(), session.getIdentity(), session.getAccessControlContext(), viewName);
accessControl.checkCanCreateView(session.getRequiredTransactionId(), session.getIdentity(), session.getAccessControlContext(), viewName);
Map<NodeRef<Parameter>, Expression> parameterLookup = parameterExtractor(statement, parameters);
Analyzer analyzer = new Analyzer(session, metadata, sqlParser, accessControl, Optional.empty(), parameters, parameterLookup, warningCollector, query, new ViewDefinitionReferences());
Analysis analysis = analyzer.analyzeSemantic(statement, false);
checkAccessPermissions(analysis.getAccessControlReferences(), analysis.getViewDefinitionReferences(), query, session.getPreparedStatements(), session.getIdentity(), accessControl, session.getAccessControlContext());
List<ColumnMetadata> columnMetadata = analysis.getOutputDescriptor(statement.getQuery())
.getVisibleFields().stream()
.map(field -> ColumnMetadata.builder()
.setName(metadata.normalizeIdentifier(session, viewName.getCatalogName(), field.getName().get()))
.setType(field.getType())
.build())View on GitHub (pinned to 55bb57d202)
Solutions
- Add IF NOT EXISTS to make the statement idempotent: CREATE MATERIALIZED VIEW IF NOT EXISTS ...
- DROP MATERIALIZED VIEW (or table) with the same name first if replacement is intended
- Use OR REPLACE if supported by your connector to replace the existing definition
- Make deployment scripts idempotent so re-runs don't collide
Example fix
// before CREATE MATERIALIZED VIEW hive.default.mv_daily AS SELECT ... // after CREATE MATERIALIZED VIEW IF NOT EXISTS hive.default.mv_daily AS SELECT ...
Defensive patterns
Strategy: try-catch
Validate before calling
// check existence first, or make DDL idempotent
boolean exists = tableOrViewExists(catalog, schema, name);
if (exists && !allowReplace) {
return; // skip creation
} Try / catch
try {
execute(createMvDdl);
} catch (SemanticException e) {
if (e.getCode() == MATERIALIZED_VIEW_ALREADY_EXISTS) {
// treat as success for idempotent deployments
} else throw e;
} Prevention
- Always use CREATE MATERIALIZED VIEW IF NOT EXISTS in deployment scripts
- Generate deterministic view names to avoid cross-team collisions
- Add existence checks before creation in idempotent pipelines
- Guard scheduler retries against duplicate creation
When it happens
Trigger: Re-running a migration/deployment script that creates the same materialized view; concurrent jobs both creating the same view; the name collides with an existing table or materialized view in the connector.
Common situations: Non-idempotent CI/CD pipelines; re-running failed scripts without cleanup; two teams independently choosing the same view name; scheduler retries after a timeout when creation actually succeeded.
Related errors
- Materialized view already exists
- MATERIALIZED_VIEW_ALREADY_EXISTS
- INVALID_TABLE_PROPERTY
- NOT_SUPPORTED
- View already exists
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/f58ba10a053a11f1.
Report an issue: GitHub.