apache/seatunnel · error · OptionValidationException

Cannot specify both '%s' and root-level '%s'.

Error message

Cannot specify both '%s' and root-level '%s'.

What it means

RabbitmqTableConfigsValidator.evaluate throws OptionValidationException when both tables-configs entries and a root-level schema are present. The two mechanisms are mutually exclusive: either one schema for a single queue, or per-table configs each with their own schema.

Source

Thrown at seatunnel-connectors-v2/connector-rabbitmq/src/main/java/org/apache/seatunnel/connectors/seatunnel/rabbitmq/config/RabbitmqTableConfigsValidator.java:56

    private static final String QUEUE_NAME_KEY = RabbitmqBaseOptions.QUEUE_NAME.key();
    private static final String SCHEMA_KEY = RabbitmqBaseOptions.SCHEMA.key();

    @Override
    public String description() {
        return "requires each entry to declare a non-blank '"
                + QUEUE_NAME_KEY
                + "' and a '"
                + SCHEMA_KEY
                + "', and forbids a root-level '"
                + SCHEMA_KEY
                + "'";
    }

    @Override
    public boolean evaluate(ReadonlyConfig config, List<Map<String, Object>> entries)
            throws OptionValidationException {
        if (config.getOptional(RabbitmqBaseOptions.SCHEMA).isPresent()) {
            throw new OptionValidationException(
                    "Cannot specify both '%s' and root-level '%s'.", TABLE_CONFIGS_KEY, SCHEMA_KEY);
        }
        for (int i = 0; i < entries.size(); i++) {
            ReadonlyConfig entry = ReadonlyConfig.fromMap(entries.get(i));
            String queueName = entry.getOptional(RabbitmqBaseOptions.QUEUE_NAME).orElse(null);
            if (queueName == null || queueName.trim().isEmpty()) {
                throw new OptionValidationException(
                        "%s[%d]: '%s' must be configured and non-blank",
                        TABLE_CONFIGS_KEY, i, QUEUE_NAME_KEY);
            }

            if (!entry.getOptional(RabbitmqBaseOptions.SCHEMA).isPresent()) {
                throw new OptionValidationException(
                        "%s[%d]: '%s' must be configured", TABLE_CONFIGS_KEY, i, SCHEMA_KEY);
            }
        }

        return true;

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Remove the root-level schema option when using tables-configs
  2. Keep schema definitions inside each tables-configs entry instead
  3. Re-run the job after cleaning up so only one schema mechanism is active

Example fix

// before
source {
  RabbitMQ {
    schema = { fields { id = int } }
    tables-configs = [
      { queue-name = "q1", schema = { fields { id = int } } }
    ]
  }
}
// after
source {
  RabbitMQ {
    tables-configs = [
      { queue-name = "q1", schema = { fields { id = int } } }
    ]
  }
}
Defensive patterns

Strategy: validation

Validate before calling

ReadonlyConfig cfg = ReadonlyConfig.fromMap(jobConfig);
if (cfg.getOptional(RabbitmqBaseOptions.TABLE_CONFIGS).isPresent()
    && cfg.getOptional(RabbitmqBaseOptions.SCHEMA).isPresent()) {
  throw new IllegalArgumentException("Remove root-level schema when tables-configs is used");
}

Try / catch

try {
  tablesConfigsValidator.evaluate(config, entries);
} catch (OptionValidationException e) {
  System.err.println("Conflicting options: " + e.getMessage());
}

Prevention

When it happens

Trigger: User defines tables-configs with entries but also keeps schema at the root of the source config; both keys present in the same HOCON/JSON config.

Common situations: Migrating a single-queue config to multi-table mode: user added tables-configs but forgot to delete the old root schema block; merged configs from two examples.

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/60b076f48a31a335. Report an issue: GitHub.