{"record":{"id":"91a06f33aa2b9854","repo":"apache/seatunnel","slug":"columnalreadyexistexception","errorCode":null,"errorMessage":"ColumnAlreadyExistException: {}","messagePattern":"ColumnAlreadyExistException: (.+?)","errorType":"exception","errorClass":"CatalogException","httpStatus":null,"severity":"error","filePath":"seatunnel-connectors-v2/connector-paimon/src/main/java/org/apache/seatunnel/connectors/seatunnel/paimon/catalog/PaimonCatalog.java","lineNumber":368,"sourceCode":"        return (PaimonCatalog)\n                catalogFactory.createCatalog(catalogFactory.factoryIdentifier(), readonlyConfig);\n    }\n\n    // --------------------------------------------------------------------------------------------\n    // alterTable\n    // --------------------------------------------------------------------------------------------\n\n    public void alterTable(\n            Identifier identifier, SchemaChange schemaChange, boolean ignoreIfNotExists) {\n        try {\n            catalog.alterTable(identifier, schemaChange, ignoreIfNotExists);\n        } catch (org.apache.paimon.catalog.Catalog.TableNotExistException e) {\n            throw new TableNotExistException(\n                    this.catalogName,\n                    TablePath.of(identifier.getDatabaseName(), identifier.getTableName()),\n                    e);\n        } catch (org.apache.paimon.catalog.Catalog.ColumnAlreadyExistException e) {\n            throw new CatalogException(\"ColumnAlreadyExistException: {}\", e);\n        } catch (org.apache.paimon.catalog.Catalog.ColumnNotExistException e) {\n            throw new CatalogException(\"ColumnNotExistException: {}\", e);\n        }\n    }\n\n    public void alterTable(\n            Identifier identifier, List<SchemaChange> schemaChanges, boolean ignoreIfNotExists) {\n        try {\n            catalog.alterTable(identifier, schemaChanges, ignoreIfNotExists);\n        } catch (org.apache.paimon.catalog.Catalog.TableNotExistException e) {\n            throw new TableNotExistException(\n                    this.catalogName,\n                    TablePath.of(identifier.getDatabaseName(), identifier.getTableName()),\n                    e);\n        } catch (org.apache.paimon.catalog.Catalog.ColumnAlreadyExistException e) {\n            throw new CatalogException(\"ColumnAlreadyExistException: {}\", e);\n        } catch (org.apache.paimon.catalog.Catalog.ColumnNotExistException e) {\n            throw new CatalogException(\"ColumnNotExistException: {}\", e);","sourceCodeStart":350,"sourceCodeEnd":386,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-paimon/src/main/java/org/apache/seatunnel/connectors/seatunnel/paimon/catalog/PaimonCatalog.java#L350-L386","documentation":"SeaTunnel's PaimonCatalog wraps Paimon's org.apache.paimon.catalog.Catalog.ColumnAlreadyExistException and rethrows it as a generic CatalogException with the message \"ColumnAlreadyExistException: {}\". It means an ALTER TABLE schema change tried to ADD a column whose name already exists in the Paimon table schema. The {} is a literal placeholder that is never substituted (no MessageFormat applied), so the real column name is only available in the wrapped cause.","triggerScenarios":"Calling catalog.alterTable(identifier, schemaChanges, ignoreIfNotExists) (or the 2-arg overload) with a SchemaChange.AddColumn whose field name already exists in the target Paimon table, and the Paimon catalog is not called with ignoreIfNotExists=true / SchemaChange is not marked as ignore.","commonSituations":"Running schema-evolution pipelines that add columns idempotently across job restarts; two concurrent jobs both adding the same column; re-running a DDL migration script that was partially applied; human typo where the new column name collides with an existing one (case-sensitivity differences between engines).","solutions":["Check the target table's current schema (e.g. via Paimon catalog SHOW CREATE TABLE / schema) and remove or rename the duplicate AddColumn change.","Make the schema change idempotent: skip AddColumn when the column already exists, or use Paimon's ignore-if-not-exists variant of alterTable.","Catch CatalogException in the caller, inspect the cause for ColumnAlreadyExistException, and treat it as a no-op if the existing column is compatible.","Serialize DDL so concurrent jobs cannot add the same column simultaneously."],"exampleFix":"// before\nchanges.add(SchemaChange.addColumn(\"amount\", DataTypes.DOUBLE()));\ncatalog.alterTable(identifier, changes);\n// after\nif (!existingFieldNames.contains(\"amount\")) {\n    changes.add(SchemaChange.addColumn(\"amount\", DataTypes.DOUBLE()));\n}\ncatalog.alterTable(identifier, changes);","handlingStrategy":"validation","validationCode":"Schema tableSchema = catalog.getTable(identifier);\nboolean exists = tableSchema.fields().stream()\n        .anyMatch(f -> f.name().equalsIgnoreCase(\"amount\"));\nif (exists) { /* skip AddColumn */ }","typeGuard":null,"tryCatchPattern":"try {\n    catalog.alterTable(identifier, changes);\n} catch (CatalogException e) {\n    if (e.getCause() instanceof org.apache.paimon.catalog.Catalog.ColumnAlreadyExistException) {\n        LOG.warn(\"column already exists, skipping\");\n    } else { throw e; }\n}","preventionTips":["Fetch the current schema before building AddColumn changes","Deduplicate schema change lists","Run DDL from a single coordinator, not from every worker","Make migrations idempotent so restarts are safe"],"tags":["paimon","schema-evolution","duplicate-column","alter-table"],"backgroundTag":"file-already-exists","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}