{"record":{"id":"bab0251344f9cbad","repo":"apache/iceberg","slug":"view-already-exists-s","errorCode":null,"errorMessage":"View already exists: %s","messagePattern":"View already exists: (.+?)","errorType":"exception","errorClass":"AlreadyExistsException","httpStatus":409,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/inmemory/InMemoryCatalog.java","lineNumber":517,"sourceCode":"      String oldLocation = base == null ? null : currentMetadataLocation();\n\n      synchronized (InMemoryCatalog.this) {\n        if (null == base && !namespaceExists(identifier.namespace())) {\n          throw new NoSuchNamespaceException(\n              \"Cannot create view %s. Namespace does not exist: %s\",\n              identifier, identifier.namespace());\n        }\n\n        if (tables.containsKey(identifier)) {\n          throw new AlreadyExistsException(\"Table with same name already exists: %s\", identifier);\n        }\n\n        views.compute(\n            identifier,\n            (k, existingLocation) -> {\n              if (!Objects.equal(existingLocation, oldLocation)) {\n                if (null == base) {\n                  throw new AlreadyExistsException(\"View already exists: %s\", identifier);\n                }\n\n                if (null == existingLocation) {\n                  throw new NoSuchViewException(\"View does not exist: %s\", identifier);\n                }\n\n                throw new CommitFailedException(\n                    \"Cannot commit to view %s metadata location from %s to %s \"\n                        + \"because it has been concurrently modified to %s\",\n                    identifier, oldLocation, newLocation, existingLocation);\n              }\n\n              return newLocation;\n            });\n      }\n    }\n\n    @Override","sourceCodeStart":499,"sourceCodeEnd":535,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/inmemory/InMemoryCatalog.java#L499-L535","documentation":"Inside the views.compute lambda of the view commit path, if the expected location does not match and base is null (a create), a view under this name was created concurrently. InMemoryCatalog throws AlreadyExistsException instead of overwriting the winner, keeping create operations idempotent-safe under races.","triggerScenarios":"Two concurrent createView/buildView(...).create() calls for the same identifier: one inserts first; the other finds existingLocation != null while its base == null.","commonSituations":"Parallel test fixtures creating the same view; duplicate scheduled jobs; idempotent retry of a create that actually succeeded the first time.","solutions":["Deduplicate view-creation calls across threads/jobs.","Catch AlreadyExistsException and treat as success, optionally loading the view to verify it matches expectations.","Use a check-then-create guarded by external locking if creation must be exclusive."],"exampleFix":"// before\ncatalog.buildView(ident).withQuery(\"spark\", q).create();\n\n// after\ntry {\n  catalog.buildView(ident).withQuery(\"spark\", q).create();\n} catch (AlreadyExistsException e) {\n  catalog.loadView(ident); // concurrent create won\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { viewBuilder.create(); } catch (AlreadyExistsException e) { View existing = catalog.loadView(ident); // verify or adopt concurrent creation }","preventionTips":["Guard concurrent creates with an in-process lock or identifier set","Treat AlreadyExistsException as success in idempotent create flows","Avoid duplicate scheduled jobs creating the same view"],"tags":["catalog","concurrency","create-view","race-condition"],"backgroundTag":"entity-already-exists","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"}