{"record":{"id":"9500f70145075847","repo":"apache/seatunnel","slug":"table-name-tablenames-must-be-unique","errorCode":null,"errorMessage":"table name: <tableNames> must be unique","messagePattern":"table name: <tableNames> must be unique","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"seatunnel-connectors-v2/connector-fake/src/main/java/org/apache/seatunnel/connectors/seatunnel/fake/config/MultipleTableFakeSourceConfig.java","lineNumber":54,"sourceCode":"    private static final long serialVersionUID = 1L;\n\n    @Getter private List<FakeConfig> fakeConfigs;\n\n    public MultipleTableFakeSourceConfig(ReadonlyConfig fakeSourceRootConfig) {\n        if (fakeSourceRootConfig.getOptional(ConnectorCommonOptions.TABLE_CONFIGS).isPresent()) {\n            parseFromConfigs(fakeSourceRootConfig);\n        } else {\n            parseFromConfig(fakeSourceRootConfig);\n        }\n        // validate\n        if (fakeConfigs.size() > 1) {\n            List<String> tableNames =\n                    fakeConfigs.stream()\n                            .map(FakeConfig::getCatalogTable)\n                            .map(catalogTable -> catalogTable.getTableId().toTablePath().toString())\n                            .collect(Collectors.toList());\n            if (CollectionUtils.size(tableNames) != new HashSet<>(tableNames).size()) {\n                throw new IllegalArgumentException(\"table name: \" + tableNames + \" must be unique\");\n            }\n        }\n    }\n\n    private void parseFromConfigs(ReadonlyConfig readonlyConfig) {\n        List<ReadonlyConfig> readonlyConfigs =\n                readonlyConfig.getOptional(ConnectorCommonOptions.TABLE_CONFIGS).get().stream()\n                        .map(ReadonlyConfig::fromMap)\n                        .collect(Collectors.toList());\n        // Use the config outside if it's not set in sub config\n        fakeConfigs =\n                readonlyConfigs.stream()\n                        .map(FakeConfig::buildWithConfig)\n                        .collect(Collectors.toList());\n    }\n\n    private void parseFromConfig(ReadonlyConfig readonlyConfig) {\n        FakeConfig fakeConfig = FakeConfig.buildWithConfig(readonlyConfig);","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-fake/src/main/java/org/apache/seatunnel/connectors/seatunnel/fake/config/MultipleTableFakeSourceConfig.java#L36-L72","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Rename duplicate table entries so each catalog table has a unique database.table name","Review the table names listed in the exception to locate the duplicates","If only one table is needed, collapse to a single-table config without the extra entries"],"exampleFix":"# before\ntables = [\n  { table-name = \"db.tbl1\" }\n  { table-name = \"db.tbl1\" }\n]\n# after\ntables = [\n  { table-name = \"db.tbl1\" }\n  { table-name = \"db.tbl2\" }\n]","handlingStrategy":"validation","validationCode":"// before building the config\nList<String> names = tableConfigs.stream()\n    .map(c -> c.getString(\"table-name\"))\n    .collect(Collectors.toList());\nif (new HashSet<>(names).size() != names.size()) {\n    throw new IllegalArgumentException(\"duplicate table names: \" + names);\n}","typeGuard":null,"tryCatchPattern":"try {\n    new MultipleTableFakeSourceConfig(readonlyConfig);\n} catch (IllegalArgumentException e) {\n    // e.getMessage() lists the table names; rename duplicates and retry\n}","preventionTips":["When generating multi-table configs programmatically, deduplicate on the fully-qualified table path","After copy-pasting table blocks, always update the table name","Use database-qualified names to avoid namespace collisions"],"tags":["fake-connector","duplicate-table","config-validation"],"backgroundTag":"conflicting-config-options","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}