apache/seatunnel · error · IllegalArgumentException

The jobId must not be empty.

Error message

The jobId must not be empty.

What it means

CheckpointHistoryServlet.doGet reads the jobId from the request path info (form /jobId). If the path is missing, empty, or only a slash, it throws IllegalArgumentException because a numeric job id is mandatory to look up checkpoint history. Long.parseLong would otherwise fail on garbage, so the explicit check guards the empty case.

Source

Thrown at seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/rest/servlet/CheckpointHistoryServlet.java:45

import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

public class CheckpointHistoryServlet extends BaseServlet {

    private final CheckpointMonitorRestService restService;

    public CheckpointHistoryServlet(NodeEngineImpl nodeEngine) {
        super(nodeEngine);
        this.restService = new CheckpointMonitorRestService(nodeEngine);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        String jobIdStr = req.getPathInfo();
        if (jobIdStr == null || jobIdStr.length() <= 1) {
            throw new IllegalArgumentException("The jobId must not be empty.");
        }
        long jobId = Long.parseLong(jobIdStr.substring(1));
        Integer pipelineId =
                req.getParameter("pipelineId") == null
                        ? null
                        : Integer.parseInt(req.getParameter("pipelineId"));
        int limit =
                req.getParameter("limit") == null
                        ? 20
                        : Integer.parseInt(req.getParameter("limit"));
        CheckpointStatus status = null;
        if (req.getParameter("status") != null) {
            status = CheckpointStatus.valueOf(req.getParameter("status").toUpperCase());
        }
        writeJson(resp, restService.getHistory(jobId, pipelineId, limit, status));
    }
}

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Append the numeric job id to the URL path, e.g. GET /checkpoint-history/<jobId>
  2. Validate the jobId is present and numeric in the client before calling
  3. Ensure proxies/gateways do not strip the trailing path segment
  4. Catch IllegalArgumentException client-side and surface a 400 with a helpful message

Example fix

// before
resp = get(base + "/checkpoint-history/"); // missing id
// after
resp = get(base + "/checkpoint-history/" + jobId); // jobId = 918273645
Defensive patterns

Strategy: validation

Validate before calling

if (jobId == null || jobId <= 0) throw new IllegalArgumentException("jobId required");
URL url = base + "/checkpoint-history/" + jobId;

Type guard

boolean hasJobId(String pathInfo) { return pathInfo != null && pathInfo.length() > 1 && pathInfo.substring(1).matches("\\d+"); }

Try / catch

try { resp = getHistory(jobId); } catch (IllegalArgumentException e) { show("Provide a numeric jobId in the path"); }

Prevention

When it happens

Trigger: GET to the checkpoint-history endpoint without a trailing /<jobId> path segment, e.g. GET /checkpoint-history/ or /checkpoint-history.

Common situations: Client omits the job id when polling history after a job failed to submit; reverse-proxy rewrites drop the path suffix; users copy the endpoint URL without appending the id; bookmarking the base URL.

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/51893cf8ce8af9ce. Report an issue: GitHub.