jenkinsci/jenkins · error · IOException

corrupt stream: negative frame length

Error message

corrupt stream: negative frame length

What it means

Thrown by PlainCLIProtocol.FramedReader when the 4-byte frame length read from the stream is negative. The protocol defines each frame as a nonnegative int length followed by a one-byte opcode and payload; a negative length is impossible in a well-formed stream and signals corruption or a version/protocol mismatch.

Source

Thrown at cli/src/main/java/hudson/cli/PlainCLIProtocol.java:136

            cis = new CountingInputStream(is);
            flightRecorder = new FlightRecorderInputStream(cis);
            dis = new DataInputStream(flightRecorder);
        }

        @Override
        public void run() {
            try {
                while (true) {
                    LOGGER.finest("reading frame");
                    int framelen;
                    try {
                        framelen = dis.readInt();
                    } catch (EOFException x) {
                        side.handleClose();
                        break; // TODO verify that we hit EOF immediately, not partway into framelen
                    }
                    if (framelen < 0) {
                        throw new IOException("corrupt stream: negative frame length");
                    }
                    LOGGER.finest("read frame length " + framelen);
                    long start = cis.getByteCount();
                    try {
                        side.handle(new DataInputStream(new BoundedInputStream(dis, /* op byte not counted */framelen + 1)));
                    } catch (ProtocolException x) {
                        LOGGER.log(Level.WARNING, null, x);
                        // but read another frame
                    } finally {
                        long actuallyRead = cis.getByteCount() - start;
                        long unread = framelen + 1 - actuallyRead;
                        if (unread > 0) {
                            LOGGER.warning(() -> "Did not read " + unread + " bytes");
                            IOUtils.skipFully(dis, unread);
                        }
                    }
                }
            } catch (ClosedChannelException x) {

View on GitHub (pinned to 2e228ff40b)

Solutions

  1. Verify the -s URL and credentials so Jenkins returns the framed protocol rather than an error/login page.
  2. Use a CLI jar version matching the controller to avoid framing disagreements.
  3. Inspect the network path for any proxy that might alter the response body.
Defensive patterns

Strategy: try-catch

Try / catch

try {
    new PlainCLIProtocol.FramedReader(connection, is).start();
} catch (IOException e) {
    if (e.getMessage().contains("negative frame length")) {
        // reconnect with a matched CLI jar version; the stream was not the expected protocol
    } else throw e;
}

Prevention

When it happens

Trigger: The bytes being read are not actually a PlainCLIProtocol stream (e.g. an HTML error page, an HTTP chunk header, or random data), or the two sides disagree on framing (one side sending Remoting, the expecting plain).

Common situations: A proxy injecting content into the CLI stream; server returning a login/error page instead of framed bytes; client and server CLI protocol versions mismatched; connection half-closed and reusing a stale socket.

Related errors


AI-assisted analysis of jenkinsci/jenkins@2e228ff40b (2026-08-14). Data as JSON: /api/errors/e8ce4f7406859952. Report an issue: GitHub.