apache/seatunnel · warning

Malformed BATCH request, missing payload separator

Error message

Malformed BATCH request, missing payload separator: {}

What it means

Logged by dispatchBatch() when a BATCH request contains no ':' separator after the command prefix, so the batch id cannot be separated from the payload. The server replies BAD_REQUEST. The wire format requires 'BATCH <id>:<payload>'.

Solutions

  1. Correct the collector to send 'BATCH <id>:<payload>' as a single newline-terminated line.
  2. Check collector serialization code to ensure the ':' separator and payload are written in the same frame.
  3. Compare client and server protocol versions.

Example fix

// before (client)
writer.write("BATCH " + id + "\n"); writer.write(payload);
// after
writer.write("BATCH " + id + ":" + payload + "\n");
Defensive patterns

Strategy: validation

Validate before calling

String cmd = "BATCH " + batchId + ":" + payload; if (!cmd.contains(":")) { throw new IllegalArgumentException("BATCH request missing ':' separator"); }

Prevention

When it happens

Trigger: receiveLoop dispatches a line starting with the BATCH prefix that has no ':' following it — e.g. 'BATCH 12' or 'BATCH' with nothing else.

Common situations: Collector splitting id and payload onto separate lines instead of one, payload serialization dropping the separator, a truncated write due to network/buffer issues, client protocol version mismatch.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

Thrown at seatunnel-connectors-v2/connector-edge-socket/src/main/java/org/apache/seatunnel/connectors/seatunnel/edgesocket/protocol/IngressProtocolHandler.java:130

        }
    }

    private String dispatchCommit(String request) {
        Long batchId = parseBatchId(request, IngressCommand.COMMIT.prefix());
        if (batchId == null || batchId <= 0) {
            log.warn(
                    "Invalid COMMIT batchId in request: {}",
                    EdgeSocketLogUtils.abbreviateForLog(request));
            return EdgeSocketResponseCode.INVALID_PARAM.getCode();
        }
        return handler.handleCommitRequest(batchId);
    }

    private String dispatchBatch(String request) {
        int separatorIndex = request.indexOf(':', IngressCommand.BATCH.prefix().length());
        if (separatorIndex < 0) {
            log.warn(
                    "Malformed BATCH request, missing payload separator: {}",
                    EdgeSocketLogUtils.abbreviateForLog(request));
            return EdgeSocketResponseCode.BAD_REQUEST.getCode();
        }
        Long batchId =
                parseBatchId(request.substring(0, separatorIndex), IngressCommand.BATCH.prefix());
        if (batchId == null || batchId <= 0) {
            log.warn(
                    "Invalid BATCH batchId in request: {}",
                    EdgeSocketLogUtils.abbreviateForLog(request));
            return EdgeSocketResponseCode.INVALID_PARAM.getCode();
        }
        String payload = request.substring(separatorIndex + 1);
        return handler.handleBatchRecord(batchId, payload);
    }

    private static boolean constantTimeEquals(String expected, String actual) {
        if (expected == null || actual == null) {
            return Objects.equals(expected, actual);

View on GitHub (pinned to cf67b549a7)