apache/seatunnel · error · IllegalArgumentException

Dry-run is only supported via CLI

Error message

Dry-run is only supported via CLI

What it means

The REST submitJob endpoint explicitly rejects the dryRun parameter because dry-run execution is only implemented in the CLI (client-side local run). Passing ?dryRun=... to the REST API throws IllegalArgumentException before any validation of the rest of the request.

Solutions

  1. Remove the dryRun parameter from the REST request
  2. Use the CLI for dry runs: sh bin/seatunnel.sh --config <config> -m local -e run --dry-run
  3. Implement validation-only checks client-side (config parsing) instead of relying on REST dry-run

Example fix

// before
POST /submit-job?dryRun=true
// after
POST /submit-job   // or use CLI: seatunnel.sh --dry-run
Defensive patterns

Strategy: validation

Validate before calling

if ('dryRun' in params || 'DRY_RUN' in params) throw new Error('use CLI for dry-run, not REST');

Try / catch

try {
    await post('/submit-job?...', body);
} catch (e) {
    if (String(e).includes('Dry-run is only supported via CLI')) {
        // strip dryRun param or switch to CLI
    }
}

Prevention

When it happens

Trigger: Calling POST /submit-job?dryRun=true (or any non-null dryRun value) on the Zeta REST API.

Common situations: Reusing CLI flags in REST calls; automated tools adding dryRun universally; docs/code examples mixing CLI and REST submission.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/rest/service/JobInfoService.java:390

        JsonArray jsonResponse = new JsonArray();
        List<Map> jobList = JsonUtils.toList(requestHandle(requestBody).toString(), Map.class);

        jobList.forEach(
                job -> {
                    handleStopJob(job, getSeaTunnelServer(false), nodeEngine.getNode());
                    jsonResponse.add(
                            new JsonObject()
                                    .add(RestConstant.JOB_ID, (Long) job.get(RestConstant.JOB_ID)));
                });

        return jsonResponse;
    }

    public JsonObject submitJob(Map<String, String> requestParams, byte[] requestBody) {

        if (requestParams.containsKey(RestConstant.DRY_RUN)
                && requestParams.get(RestConstant.DRY_RUN) != null) {
            throw new IllegalArgumentException("Dry-run is only supported via CLI");
        }
        if (Boolean.parseBoolean(requestParams.get(RestConstant.IS_START_WITH_SAVE_POINT))
                && requestParams.get(RestConstant.JOB_ID) == null) {
            throw new IllegalArgumentException("Please provide jobId when start with save point.");
        }
        validateCheckpointRestoreRequest(requestParams);
        Config config;
        ConfigFormat configFormat = ConfigFormat.fromString(requestParams.get(CONFIG_FORMAT));

        switch (configFormat) {
            case HOCON:
                config = ConfigFactory.parseString(new String(requestBody, StandardCharsets.UTF_8));
                break;
            case SQL:
                config = SqlConfigBuilder.of(new String(requestBody, StandardCharsets.UTF_8));
                break;
            case JSON:
            default:

View on GitHub (pinned to cf67b549a7)