apache/seatunnel · error · PulsarConnectorException

SeaTunnelAPIErrorCode.CONFIG_VALIDATION_FAILED

SeaTunnelAPIErrorCode.CONFIG_VALIDATION_FAILED

Error message

tables_configs cannot be empty

What it means

PulsarMultiTableConfig.parseMultiTable validates the 'tables_configs' list; an empty list provides no tables to read, so it throws PulsarConnectorException with SeaTunnelAPIErrorCode.CONFIG_VALIDATION_FAILED. At least one table entry is required for multi-table Pulsar sources.

Source

Thrown at seatunnel-connectors-v2/connector-pulsar/src/main/java/org/apache/seatunnel/connectors/seatunnel/pulsar/config/PulsarMultiTableConfig.java:132

                        topic,
                        topicPattern != null ? Pattern.compile(topicPattern) : null,
                        format,
                        startMode,
                        startTimestamp,
                        stopMode,
                        stopTimestamp,
                        resetMode,
                        subscriptionName,
                        config);

        return new PulsarMultiTableConfig(
                java.util.Collections.singletonList(tableConfig), config, false, false);
    }

    private static PulsarMultiTableConfig parseMultiTable(ReadonlyConfig config) {
        List<Map<String, Object>> tablesConfigs = config.get(TableSchemaOptions.TABLE_CONFIGS);
        if (tablesConfigs.isEmpty()) {
            throw new PulsarConnectorException(
                    SeaTunnelAPIErrorCode.CONFIG_VALIDATION_FAILED,
                    "tables_configs cannot be empty");
        }
        List<PulsarTableConfig> tableConfigs = new ArrayList<>();
        Map<String, Integer> tablePathIndexes = new LinkedHashMap<>();
        Map<String, Integer> explicitTopicIndexes = new LinkedHashMap<>();
        Map<String, Integer> topicPatternIndexes = new LinkedHashMap<>();
        List<PatternEntry> knownPatterns = new ArrayList<>();

        for (int i = 0; i < tablesConfigs.size(); i++) {
            Map<String, Object> tableConfigMap = tablesConfigs.get(i);
            ReadonlyConfig tableConfig = mergeWithGlobal(config, tableConfigMap);

            String topic = tableConfig.getOptional(PulsarSourceOptions.TOPIC).orElse(null);
            String topicPatternStr =
                    tableConfig.getOptional(PulsarSourceOptions.TOPIC_PATTERN).orElse(null);

            if ((topic == null && topicPatternStr == null)

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Populate tables_configs with at least one entry containing topic/topic-pattern, subscription.name, and schema.
  2. If you intend a single-table read, use the single-table config style (topic at top level) instead of empty tables_configs.
  3. Check templating/variable substitution isn't producing an empty list at runtime.

Example fix

// before
tables_configs = []
// after
tables_configs = [
  {
    topic = "persistent://public/default/orders"
    "subscription.name" = "seatunnel-sub"
  }
]
Defensive patterns

Strategy: validation

Validate before calling

List<Map<String,Object>> tables = config.get(TableSchemaOptions.TABLE_CONFIGS);
if (tables == null || tables.isEmpty()) throw new IllegalArgumentException("tables_configs must contain at least one entry");

Prevention

When it happens

Trigger: PulsarSource config parsed via PulsarMultiTableConfig.of where tables_configs key is present but resolves to an empty list ([]).

Common situations: User defines tables_configs = [] (or the list is produced empty by templating/env substitution) instead of configuring table entries; copy-pasting a skeleton config without filling it in.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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