apache/seatunnel · error · CatalogException
ColumnAlreadyExistException: {}
Error message
ColumnAlreadyExistException: {} What it means
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.
Source
Thrown at seatunnel-connectors-v2/connector-paimon/src/main/java/org/apache/seatunnel/connectors/seatunnel/paimon/catalog/PaimonCatalog.java:368
return (PaimonCatalog)
catalogFactory.createCatalog(catalogFactory.factoryIdentifier(), readonlyConfig);
}
// --------------------------------------------------------------------------------------------
// alterTable
// --------------------------------------------------------------------------------------------
public void alterTable(
Identifier identifier, SchemaChange schemaChange, boolean ignoreIfNotExists) {
try {
catalog.alterTable(identifier, schemaChange, ignoreIfNotExists);
} catch (org.apache.paimon.catalog.Catalog.TableNotExistException e) {
throw new TableNotExistException(
this.catalogName,
TablePath.of(identifier.getDatabaseName(), identifier.getTableName()),
e);
} catch (org.apache.paimon.catalog.Catalog.ColumnAlreadyExistException e) {
throw new CatalogException("ColumnAlreadyExistException: {}", e);
} catch (org.apache.paimon.catalog.Catalog.ColumnNotExistException e) {
throw new CatalogException("ColumnNotExistException: {}", e);
}
}
public void alterTable(
Identifier identifier, List<SchemaChange> schemaChanges, boolean ignoreIfNotExists) {
try {
catalog.alterTable(identifier, schemaChanges, ignoreIfNotExists);
} catch (org.apache.paimon.catalog.Catalog.TableNotExistException e) {
throw new TableNotExistException(
this.catalogName,
TablePath.of(identifier.getDatabaseName(), identifier.getTableName()),
e);
} catch (org.apache.paimon.catalog.Catalog.ColumnAlreadyExistException e) {
throw new CatalogException("ColumnAlreadyExistException: {}", e);
} catch (org.apache.paimon.catalog.Catalog.ColumnNotExistException e) {
throw new CatalogException("ColumnNotExistException: {}", e);View on GitHub (pinned to cf67b549a7)
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.
Example fix
// before
changes.add(SchemaChange.addColumn("amount", DataTypes.DOUBLE()));
catalog.alterTable(identifier, changes);
// after
if (!existingFieldNames.contains("amount")) {
changes.add(SchemaChange.addColumn("amount", DataTypes.DOUBLE()));
}
catalog.alterTable(identifier, changes); Defensive patterns
Strategy: validation
Validate before calling
Schema tableSchema = catalog.getTable(identifier);
boolean exists = tableSchema.fields().stream()
.anyMatch(f -> f.name().equalsIgnoreCase("amount"));
if (exists) { /* skip AddColumn */ } Try / catch
try {
catalog.alterTable(identifier, changes);
} catch (CatalogException e) {
if (e.getCause() instanceof org.apache.paimon.catalog.Catalog.ColumnAlreadyExistException) {
LOG.warn("column already exists, skipping");
} else { throw e; }
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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).
Understand the failure class
Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.
Related errors
- ColumnNotExistException: {}
- Table ${tableName} does not exist in catalog ${catalogName}
- Unsupported alter table event: ${event}
- Cannot convert field %s from type %s to %s of Paimon table %
- old: {{}-{}} and new: {{}-{}} belongs to the same type famil
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/91a06f33aa2b9854.
Report an issue: GitHub.