{"record":{"id":"f58ba10a053a11f1","repo":"prestodb/presto","slug":"materialized-view-already-exists-f58ba1","errorCode":"MATERIALIZED_VIEW_ALREADY_EXISTS","errorMessage":"Materialized view '%s' already exists","messagePattern":"Materialized view '(.+?)' already exists","errorType":"error_code","errorClass":"SemanticException","httpStatus":null,"severity":"error","filePath":"presto-main-base/src/main/java/com/facebook/presto/execution/CreateMaterializedViewTask.java","lineNumber":109,"sourceCode":"\n    @Override\n    public ListenableFuture<?> execute(CreateMaterializedView statement, TransactionManager transactionManager, Metadata metadata, AccessControl accessControl, Session session, List<Expression> parameters, WarningCollector warningCollector, String query)\n    {\n        QualifiedObjectName viewName = createQualifiedObjectName(session, statement, statement.getName(), metadata);\n        MetadataResolver metadataResolver = metadata.getMetadataResolver(session);\n\n        if (!metadataResolver.catalogExists(viewName.getCatalogName())) {\n            throw new SemanticException(MISSING_CATALOG, \"Catalog '%s' does not exist\", viewName.getCatalogName());\n        }\n\n        if (!metadataResolver.schemaExists(viewName.getCatalogSchemaName())) {\n            throw new SemanticException(MISSING_SCHEMA, statement, \"Schema '%s' does not exist\", viewName.getSchemaName());\n        }\n\n        Optional<TableHandle> viewHandle = metadataResolver.getTableHandle(viewName);\n        if (viewHandle.isPresent()) {\n            if (!statement.isNotExists()) {\n                throw new SemanticException(MATERIALIZED_VIEW_ALREADY_EXISTS, statement, \"Materialized view '%s' already exists\", viewName);\n            }\n            return immediateFuture(null);\n        }\n\n        accessControl.checkCanCreateTable(session.getRequiredTransactionId(), session.getIdentity(), session.getAccessControlContext(), viewName);\n        accessControl.checkCanCreateView(session.getRequiredTransactionId(), session.getIdentity(), session.getAccessControlContext(), viewName);\n\n        Map<NodeRef<Parameter>, Expression> parameterLookup = parameterExtractor(statement, parameters);\n        Analyzer analyzer = new Analyzer(session, metadata, sqlParser, accessControl, Optional.empty(), parameters, parameterLookup, warningCollector, query, new ViewDefinitionReferences());\n        Analysis analysis = analyzer.analyzeSemantic(statement, false);\n        checkAccessPermissions(analysis.getAccessControlReferences(), analysis.getViewDefinitionReferences(), query, session.getPreparedStatements(), session.getIdentity(), accessControl, session.getAccessControlContext());\n\n        List<ColumnMetadata> columnMetadata = analysis.getOutputDescriptor(statement.getQuery())\n                .getVisibleFields().stream()\n                .map(field -> ColumnMetadata.builder()\n                        .setName(metadata.normalizeIdentifier(session, viewName.getCatalogName(), field.getName().get()))\n                        .setType(field.getType())\n                        .build())","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-main-base/src/main/java/com/facebook/presto/execution/CreateMaterializedViewTask.java#L91-L127","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nCREATE MATERIALIZED VIEW hive.default.mv_daily AS SELECT ...\n// after\nCREATE MATERIALIZED VIEW IF NOT EXISTS hive.default.mv_daily AS SELECT ...","handlingStrategy":"try-catch","validationCode":"// check existence first, or make DDL idempotent\nboolean exists = tableOrViewExists(catalog, schema, name);\nif (exists && !allowReplace) {\n    return; // skip creation\n}","typeGuard":null,"tryCatchPattern":"try {\n    execute(createMvDdl);\n} catch (SemanticException e) {\n    if (e.getCode() == MATERIALIZED_VIEW_ALREADY_EXISTS) {\n        // treat as success for idempotent deployments\n    } else throw e;\n}","preventionTips":["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"],"tags":["materialized-view","already-exists","idempotency"],"backgroundTag":"object-already-exists","analyzedSha":"55bb57d202de3b926896fa966c2c4a44c779634e","analyzedAt":"2026-09-04T12:50:26.162Z","contentChangedAt":"2026-09-04T12:50:26.162Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}