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.

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.

Appendix: 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)