jenkinsci/jenkins · error · IOException
DataInputStream unexpectedly returned negative integer
Error message
DataInputStream unexpectedly returned negative integer
What it means
`Connection.readByteArray()` reads a 4-byte length prefix via `din.readInt()` and throws IOException if the resulting `bufSize` is negative. A negative length means the length-prefix bytes were corrupted or deliberately malformed (readInt interprets the high bit as a sign), so allocating `new byte[bufSize]` would be impossible/dangerous. This guards the CLI wire protocol against stream corruption.
Source
Thrown at core/src/main/java/hudson/cli/Connection.java:142
public void writeKey(Key key) throws IOException {
writeUTF(Base64.getEncoder().encodeToString(key.getEncoded()));
}
public X509EncodedKeySpec readKey() throws IOException {
byte[] otherHalf = Base64.getDecoder().decode(readUTF()); // for historical reasons, we don't use readByteArray()
return new X509EncodedKeySpec(otherHalf);
}
public void writeByteArray(byte[] data) throws IOException {
dout.writeInt(data.length);
dout.write(data);
}
public byte[] readByteArray() throws IOException {
int bufSize = din.readInt();
if (bufSize < 0) {
throw new IOException("DataInputStream unexpectedly returned negative integer");
}
byte[] buf = new byte[bufSize];
din.readFully(buf);
return buf;
}
/**
* Performs a Diffie-Hellman key exchange and produce a common secret between two ends of the connection.
*
* <p>
* DH is also useful as a coin-toss algorithm. Two parties get the same random number without trusting
* each other.
*/
public KeyAgreement diffieHellman(boolean side) throws IOException, GeneralSecurityException {
return diffieHellman(side, 512);
}
public KeyAgreement diffieHellman(boolean side, int keySize) throws IOException, GeneralSecurityException {View on GitHub (pinned to 2e228ff40b)
Solutions
- Ensure the `jenkins-cli.jar` matches the Jenkins server version exactly (download it from your server's /jnlpJars/jenkins-cli.jar).
- Remove or reconfigure any HTTP/TCP proxy in front of Jenkins that may corrupt binary framing; connect directly to test.
- If you control both endpoints, verify the write side always emits `writeByteArray` (length-prefixed) matching the read side, and check for stream desynchronization after a prior error.
Example fix
// before: mismatched jar causes negative length prefix // java -jar old-jenkins-cli.jar -s https://jenkins help // -> IOException: DataInputStream unexpectedly returned negative integer // // after: use the jar shipped by this server // curl -O https://jenkins/jnlpJars/jenkins-cli.jar // java -jar jenkins-cli.jar -s https://jenkins help
Defensive patterns
Strategy: try-catch
Validate before calling
// Ensure CLI jar and server versions match before connecting: // download the jar from the same server: curl -O $JENKINS/jnlpJars/jenkins-cli.jar
Try / catch
try {
byte[] data = conn.readByteArray();
} catch (IOException e) {
if (e.getMessage().contains("negative integer")) {
// protocol/stream desync or version mismatch: reconnect with a fresh,
// version-matched CLI jar rather than reusing the broken stream
throw new IllegalStateException("CLI protocol framing corrupted; "
+ "use the jenkins-cli.jar matching server version and bypass proxies", e);
}
throw e;
} Prevention
- Always use the jenkins-cli.jar downloaded from the target Jenkins server.
- Avoid HTTP proxies that may alter binary framing for CLI traffic.
When it happens
Trigger: Any CLI exchange that calls `readByteArray()` when the peer sent a malformed length prefix, or when the stream has desynchronized (partial/missing bytes), or when a version/protocol mismatch causes the reader to interpret payload data as a length. Also reachable under a man-in-the-middle injecting garbage.
Common situations: CLI jar version mismatched with the Jenkins server (different framing), a proxy/load balancer truncating or rewriting the binary stream, network corruption, or an attacker tampering with the connection.
Related errors
- Unknown public key type:
- expected to see initial zero byte; perhaps you are connectin
- Could not get TcpSlaveAgentListener host name
- Cannot build {0} because its configuration has not been save
- Build scheduling Refused by an extension, hence not in Queue
AI-assisted analysis of jenkinsci/jenkins@2e228ff40b (2026-08-14).
Data as JSON: /api/errors/cb4177d319d461c0.
Report an issue: GitHub.