dotnet/aspnetcore · error · RuntimeException
Messages over 2GB in size are not supported
Error message
Messages over 2GB in size are not supported
What it means
readLengthHeader caps the supported payload size at 2 GB (Integer.MAX_VALUE, 0x7FFFFFFF). After reading up to 5 VarInt bytes, if the continuation bit is still set or the 5th byte exceeds 0x07, the decoded length would overflow a signed int, so the frame is rejected.
Solutions
- Treat as a malformed/fatal frame: drop the connection and reconnect.
- If you actually stream large data, chunk it through SignalR streaming (StreamItem) instead of one huge message.
- Add an inbound size cap before invoking readLengthHeader to reject absurd values early.
Example fix
// before - parse untrusted buffer directly
int len = Utils.readLengthHeader(buffer);
// after - sanity-cap first
int len = Utils.readLengthHeader(buffer);
if (len < 0 || len > MAX_ALLOWED) throw new IOException("Frame too large: " + len); Defensive patterns
Strategy: validation
Validate before calling
final int MAX_FRAME = 64 * 1024 * 1024; // pick a sane cap
int len = Utils.readLengthHeader(buffer);
if (len < 0 || len > MAX_FRAME) {
throw new java.io.IOException("Rejecting oversize/corrupt frame length: " + len);
} Type guard
static boolean isPlausibleLength(int len) {
return len >= 0 && len <= MAX_FRAME;
} Try / catch
try {
int len = Utils.readLengthHeader(buffer);
} catch (RuntimeException ex) {
if (ex.getMessage().contains("over 2GB")) {
// corrupt length header or malicious input - drop connection
connection.dispose();
}
throw ex;
} Prevention
- Apply an inbound frame-size cap before reading the length header.
- Stream large payloads via SignalR streaming instead of one giant message.
- Treat a 2GB-length error as corrupt framing, not a real payload.
When it happens
Trigger: The VarInt length prefix decodes to a value larger than 2 GiB, either because the payload genuinely exceeds that size or - far more commonly - because the length bytes are corrupt and decode to a huge number (Utils.java:43-46).
Common situations: Corrupted framing where random bytes with the high bit set are interpreted as a multi-byte length; a peer injecting garbage; rarely, an attempt to send a legitimately enormous payload.
Related errors
- MessagePack message was length
- The length header was incomplete
- Cannot read message size.
- Error reading length header.
- Error reading MessagePack data.
AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11).
Data as JSON: /api/errors/c23c91602b1b058b.
Report an issue: GitHub.
Appendix: source
Thrown at src/SignalR/clients/java/signalr/messagepack/src/main/java/com/microsoft/signalr/messagepack/Utils.java:45
int length = 0;
int numBytes = 0;
int maxLength = 5;
byte curr;
do {
// If we run out of bytes before we finish reading the length header, the message is malformed
if (buffer.hasRemaining()) {
curr = buffer.get();
} else {
throw new RuntimeException("The length header was incomplete");
}
length = length | (curr & (byte) 0x7f) << (numBytes * 7);
numBytes++;
} while (numBytes < maxLength && (curr & (byte) 0x80) != 0);
// Max header length is 5, and the maximum value of the 5th byte is 0x07
if ((curr & (byte) 0x80) != 0 || (numBytes == maxLength && curr > (byte) 0x07)) {
throw new RuntimeException("Messages over 2GB in size are not supported");
}
return length;
}
public static ArrayList<Byte> getLengthHeader(int length) {
// This code writes length prefix of the message as a VarInt. Read the comment in
// the readLengthHeader for details.
ArrayList<Byte> header = new ArrayList<Byte>();
do {
byte curr = (byte) (length & 0x7f);
length >>= 7;
if (length > 0) {
curr |= 0x80;
}
header.add(curr);
} while (length > 0);View on GitHub (pinned to 3600ca084e)