apache/seatunnel · error · IllegalArgumentException

table name: must be unique

Error message

table name: <tableNames> must be unique

What it means

MultipleTableFakeSourceConfig requires every table defined in a multi-table FakeSource config to have a unique fully-qualified table name (tableId.toTablePath()). If duplicates are detected (list size != HashSet size), an IllegalArgumentException listing all table names is thrown during construction.

Solutions

  1. Rename duplicate table entries so each catalog table has a unique database.table name
  2. Review the table names listed in the exception to locate the duplicates
  3. If only one table is needed, collapse to a single-table config without the extra entries

Example fix

# before
tables = [
  { table-name = "db.tbl1" }
  { table-name = "db.tbl1" }
]
# after
tables = [
  { table-name = "db.tbl1" }
  { table-name = "db.tbl2" }
]
Defensive patterns

Strategy: validation

Validate before calling

// before building the config
List<String> names = tableConfigs.stream()
    .map(c -> c.getString("table-name"))
    .collect(Collectors.toList());
if (new HashSet<>(names).size() != names.size()) {
    throw new IllegalArgumentException("duplicate table names: " + names);
}

Try / catch

try {
    new MultipleTableFakeSourceConfig(readonlyConfig);
} catch (IllegalArgumentException e) {
    // e.getMessage() lists the table names; rename duplicates and retry
}

Prevention

When it happens

Trigger: A FakeSource config with multiple table entries (e.g. 'tables' list or replicated ReadonlyConfig sections) where two or more entries define the same database.table identifier; triggered in the MultipleTableFakeSourceConfig constructor.

Common situations: Copy-pasting a table block and forgetting to change the table name, generating configs via script that emits duplicate entries, or case/namespace confusion where entries resolve to the same TablePath.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


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

Appendix: source

Thrown at seatunnel-connectors-v2/connector-fake/src/main/java/org/apache/seatunnel/connectors/seatunnel/fake/config/MultipleTableFakeSourceConfig.java:54

    private static final long serialVersionUID = 1L;

    @Getter private List<FakeConfig> fakeConfigs;

    public MultipleTableFakeSourceConfig(ReadonlyConfig fakeSourceRootConfig) {
        if (fakeSourceRootConfig.getOptional(ConnectorCommonOptions.TABLE_CONFIGS).isPresent()) {
            parseFromConfigs(fakeSourceRootConfig);
        } else {
            parseFromConfig(fakeSourceRootConfig);
        }
        // validate
        if (fakeConfigs.size() > 1) {
            List<String> tableNames =
                    fakeConfigs.stream()
                            .map(FakeConfig::getCatalogTable)
                            .map(catalogTable -> catalogTable.getTableId().toTablePath().toString())
                            .collect(Collectors.toList());
            if (CollectionUtils.size(tableNames) != new HashSet<>(tableNames).size()) {
                throw new IllegalArgumentException("table name: " + tableNames + " must be unique");
            }
        }
    }

    private void parseFromConfigs(ReadonlyConfig readonlyConfig) {
        List<ReadonlyConfig> readonlyConfigs =
                readonlyConfig.getOptional(ConnectorCommonOptions.TABLE_CONFIGS).get().stream()
                        .map(ReadonlyConfig::fromMap)
                        .collect(Collectors.toList());
        // Use the config outside if it's not set in sub config
        fakeConfigs =
                readonlyConfigs.stream()
                        .map(FakeConfig::buildWithConfig)
                        .collect(Collectors.toList());
    }

    private void parseFromConfig(ReadonlyConfig readonlyConfig) {
        FakeConfig fakeConfig = FakeConfig.buildWithConfig(readonlyConfig);

View on GitHub (pinned to cf67b549a7)