{"record":{"id":"1842e9daa3217d8f","repo":"apache/iceberg","slug":"view-was-created-concurrently-s","errorCode":null,"errorMessage":"View was created concurrently: %s","messagePattern":"View was created concurrently: (.+?)","errorType":"exception","errorClass":"AlreadyExistsException","httpStatus":409,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/view/BaseMetastoreViewCatalog.java","lineNumber":216,"sourceCode":"              .defaultNamespace(defaultNamespace)\n              .defaultCatalog(defaultCatalog)\n              .timestampMillis(System.currentTimeMillis())\n              .putAllSummary(EnvironmentContext.get())\n              .build();\n\n      properties.putAll(viewOverrideProperties());\n\n      ViewMetadata viewMetadata =\n          ViewMetadata.builder()\n              .setProperties(properties)\n              .setLocation(null != location ? location : defaultWarehouseLocation(identifier))\n              .setCurrentVersion(viewVersion, schema)\n              .build();\n\n      try {\n        ops.commit(null, viewMetadata);\n      } catch (CommitFailedException ignored) {\n        throw new AlreadyExistsException(\"View was created concurrently: %s\", identifier);\n      }\n\n      return new BaseView(ops, ViewUtil.fullViewName(name(), identifier));\n    }\n\n    private View replace(ViewOperations ops) {\n      if (tableExists(identifier)) {\n        throw new AlreadyExistsException(\"Table with same name already exists: %s\", identifier);\n      }\n\n      if (null == ops.current()) {\n        throw new NoSuchViewException(\"View does not exist: %s\", identifier);\n      }\n\n      Preconditions.checkState(\n          !representations.isEmpty(), \"Cannot replace view without specifying a query\");\n      Preconditions.checkState(null != schema, \"Cannot replace view without specifying schema\");\n      Preconditions.checkState(","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/view/BaseMetastoreViewCatalog.java#L198-L234","documentation":"When creating a view, the builder commits from a null base metadata. If the metastore's optimistic concurrency check raises CommitFailedException (another process created the view in the meantime), the library converts it to AlreadyExistsException('View was created concurrently') since the null-base commit only succeeds for a fresh view.","triggerScenarios":"Two concurrent create() calls (or create racing another writer) for the same view identifier; the loser's ops.commit(null, metadata) fails with CommitFailedException.","commonSituations":"Multiple schedulers/workers running the same DDL job simultaneously; CI pipelines racing to provision views.","solutions":["Catch AlreadyExistsException and treat the existing view as the outcome (idempotent create)","Retry loadView/createOrReplace after the conflict","Use external locking or a single provisioning job to avoid concurrent DDL"],"exampleFix":"// before\nview = catalog.buildView(ident).withQuery(\"sql\", q).create();\n// after\ntry {\n  view = catalog.buildView(ident).withQuery(\"sql\", q).create();\n} catch (AlreadyExistsException e) {\n  view = catalog.loadView(ident); // created concurrently\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { return builder.create(); } catch (AlreadyExistsException e) { return catalog.loadView(identifier); /* concurrent creation won */ }","preventionTips":["Make view creation idempotent: treat AlreadyExistsException as success and load the view","Run DDL provisioning from a single scheduler instance","Use retry with small backoff for concurrent DDL"],"tags":["catalog","view","concurrency"],"backgroundTag":"invalid-state-transition","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}