apache/seatunnel · error · IllegalArgumentException

env. .mode=ROUTE requires env. .sink.plugin_name to be…

Error message

env.%s.mode=ROUTE requires env.%s.sink.plugin_name to be configured.

What it means

IllegalArgumentException from ErrorHandlerConfigUtil.buildStageConfig when a stage's error-handler mode is ROUTE but no error-sink writer is configured (sinkConfig null or not configured). ROUTE mode must know where to send bad rows, so the job is rejected at config validation.

Solutions

  1. Add sink { plugin_name = "..." } under the stage error-handler block (e.g. Console, JDBC, File).
  2. Verify the exact env key prefix matches the stage key shown in the error message.
  3. Switch mode to FAIL or IGNORE if you don't actually need to route bad rows.

Example fix

// before
error-handler { mode = ROUTE }
// after
error-handler { mode = ROUTE
  sink { plugin_name = "Console" } }
Defensive patterns

Strategy: validation

Validate before calling

if ("ROUTE".equalsIgnoreCase(mode) && !config.hasPath("sink.plugin_name")) {
  throw new IllegalArgumentException("mode=ROUTE requires error-handler sink.plugin_name");
}

Try / catch

try { buildStageConfig(stage, global); } catch (IllegalArgumentException e) { if (e.getMessage().contains("ROUTE requires")) { addSinkPluginName(); } }

Prevention

When it happens

Trigger: Setting env.<stage>.mode = ROUTE (or global mode=ROUTE) without env.<stage>.sink.plugin_name (or a sufficiently complete sink block).

Common situations: Copy-pasting a stage config and forgetting the sink sub-block; specifying sink options like plugin_type but omitting plugin_name; global DISABLE config edited to ROUTE without adding a sink.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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

Appendix: source

Thrown at seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/task/error/ErrorHandlerConfigUtil.java:107

        boolean includeStacktrace = getBoolean(stage, global, "include_stacktrace", false);
        boolean includeOriginalData = getBoolean(stage, global, "include_original_data", false);

        String dataFormatStr = getString(stage, global, "original_data_format", "TEXT");
        if (!"TEXT".equalsIgnoreCase(dataFormatStr)) {
            throw new IllegalArgumentException(
                    "Unsupported original_data_format='"
                            + dataFormatStr
                            + "'. Current version only supports TEXT.");
        }
        OriginalDataFormat originalDataFormat = OriginalDataFormat.TEXT;

        int originalDataMaxLength =
                getNonNegativeInt(stage, global, "original_data_max_length", 8192);

        ErrorSinkConfig sinkConfig = buildErrorSinkConfig(stage, global);

        if (mode == ErrorHandlerMode.ROUTE && (sinkConfig == null || !sinkConfig.isConfigured())) {
            throw new IllegalArgumentException(
                    String.format(
                            "env.%s.mode=ROUTE requires env.%s.sink.plugin_name to be configured.",
                            stageKey, stageKey));
        }

        return StageErrorConfig.builder()
                .mode(mode)
                .sink(sinkConfig)
                .maxErrorRatio(maxErrorRatio)
                .maxErrorRatioMinRecords(maxErrorRatioMinRecords)
                .maxErrorRecords(maxErrorRecords)
                .queueCapacity(queueCapacity)
                .queueOverflowPolicy(overflowPolicy)
                .includeStacktrace(includeStacktrace)
                .includeOriginalData(includeOriginalData)
                .originalDataFormat(originalDataFormat)
                .originalDataMaxLength(originalDataMaxLength)
                .build();

View on GitHub (pinned to cf67b549a7)