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

  1. Check the target table's current schema (e.g. via Paimon catalog SHOW CREATE TABLE / schema) and remove or rename the duplicate AddColumn change.
  2. Make the schema change idempotent: skip AddColumn when the column already exists, or use Paimon's ignore-if-not-exists variant of alterTable.
  3. Catch CatalogException in the caller, inspect the cause for ColumnAlreadyExistException, and treat it as a no-op if the existing column is compatible.
  4. 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

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


AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10). Data as JSON: /api/errors/91a06f33aa2b9854. Report an issue: GitHub.