apache/seatunnel · error · IllegalArgumentException

jobId cannot be empty.

Error message

jobId cannot be empty.

What it means

handleStopJob requires a jobId field in the parsed request body. If map.get(RestConstant.JOB_ID) is null, it throws IllegalArgumentException("jobId cannot be empty.") since the stop operation cannot identify which job to stop.

Source

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

    protected JsonNode requestHandle(byte[] requestBody) {
        if (requestBody.length == 0) {
            throw new IllegalArgumentException("Request body is empty.");
        }
        JsonNode requestBodyJsonNode;
        try {
            requestBodyJsonNode = RestUtil.convertByteToJsonNode(requestBody);
        } catch (IOException e) {
            throw new IllegalArgumentException("Invalid JSON format in request body.");
        }
        return requestBodyJsonNode;
    }

    protected void handleStopJob(
            Map<String, Object> map, SeaTunnelServer seaTunnelServer, Node node) {
        boolean isStopWithSavePoint = false;
        if (map.get(RestConstant.JOB_ID) == null) {
            throw new IllegalArgumentException("jobId cannot be empty.");
        }
        long jobId = Long.parseLong(map.get(RestConstant.JOB_ID).toString());
        if (map.get(RestConstant.IS_STOP_WITH_SAVE_POINT) != null) {
            isStopWithSavePoint =
                    Boolean.parseBoolean(map.get(RestConstant.IS_STOP_WITH_SAVE_POINT).toString());
        }
        boolean forceStop = false;
        if (map.get(RestConstant.FORCE) != null) {
            forceStop = Boolean.parseBoolean(map.get(RestConstant.FORCE).toString());
        }

        if (!seaTunnelServer.isMasterNode()) {
            if (forceStop) {
                NodeEngineUtil.sendOperationToMasterNode(
                                node.nodeEngine, new CancelJobOperation(jobId, true))
                        .join();
                return;
            }

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Include jobId in the JSON body: {"jobId":"<running-job-id>"}
  2. Get the correct jobId from GET /running-jobs before stopping
  3. Check field naming matches RestConstant.JOB_ID ("jobId") exactly

Example fix

// before
{"isStopWithSavePoint": true}
// after
{"jobId": "863300353636515841", "isStopWithSavePoint": true}
Defensive patterns

Strategy: validation

Validate before calling

if (payload.jobId == null || payload.jobId === '') throw new Error('jobId is required to stop a job');

Try / catch

try {
    await post('/stop-job', payload);
} catch (e) {
    if (String(e).includes('jobId cannot be empty')) {
        // fetch running-jobs and set jobId
    }
}

Prevention

When it happens

Trigger: POST /stop-job (or similar) with a JSON body lacking the jobId key, or containing it as null.

Common situations: Copy-pasted body template with placeholder not replaced; wrong field name (e.g. job_id instead of jobId); jobId lost by client serialization.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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