apache/druid · error · IllegalStateException
Invalid midstream marker
Error message
Invalid midstream marker (id = %s, position = %d)
What it means
In the FRAMES stream part, every byte read at a marker position must be a valid frame marker (a data frame marker or MARKER_NO_MORE_FRAMES). Any other byte indicates the stream is not aligned to frame boundaries, so the reader throws with the channel id and byte position. This catches desynchronization or corruption mid-stream.
Solutions
- Regenerate the stream/file and retry the stage.
- Confirm only one writer owns the channel and files aren't shared across tasks.
- Check disk/filesystem integrity for the spool directory.
- Compare Druid versions of writer and reader.
Defensive patterns
Strategy: try-catch
Try / catch
try { rac = channel.read(); } catch (ISE e) { if (e.getMessage().startsWith("Invalid midstream marker")) { failStage("frame stream misaligned", e); } else { throw e; } } Prevention
- Single writer per stream file; never append from multiple tasks.
- Read frames strictly through the channel API to keep byte alignment.
- Verify spool storage integrity periodically.
When it happens
Trigger: updateStreamState reads a marker byte in StreamPart.FRAMES that is neither a frame marker nor FrameFileWriter.MARKER_NO_MORE_FRAMES.
Common situations: Corrupted spool files on disk; two writers appending to the same stream; wrong file passed to ReadableByteChunksFrameChannel; byte offset drift due to earlier skipped/failed read.
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
- Cannot read frame of size [%,d] bytes
- Invalid frame size (size = %,d B)
- Invalid stream header
- Unexpected marker type
- Cannot copy [%,d] bytes, only have [%,d] buffered
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/a03e9f4f46214fab.
Report an issue: GitHub.
Appendix: source
Thrown at processing/src/main/java/org/apache/druid/frame/channel/ReadableByteChunksFrameChannel.java:435
// Read nextFrameLength if needed; otherwise do nothing.
// Both MARKER_FRAME and MARKER_RAC use the same compression envelope format.
final int bytesRequiredToReadLength = FRAME_MARKER_BYTES + FrameCompression.COMPRESSED_DATA_HEADER_SIZE;
if (nextCompressedFrameLength == UNKNOWN_LENGTH && bytesBuffered >= bytesRequiredToReadLength) {
nextMarkerType = markerByte;
nextCompressedFrameLength = copyFromQueuedChunks(bytesRequiredToReadLength)
.getLong(FRAME_MARKER_BYTES + Byte.BYTES /* Compression strategy byte */);
if (nextCompressedFrameLength <= 0 || nextCompressedFrameLength >= MAX_FRAME_SIZE_BYTES) {
throw new ISE("Invalid frame size (size = %,d B)", nextCompressedFrameLength);
}
}
} else if (markerByte == FrameFileWriter.MARKER_NO_MORE_FRAMES) {
streamPart = StreamPart.FOOTER;
nextCompressedFrameLength = UNKNOWN_LENGTH;
nextMarkerType = NO_MARKER;
} else {
throw new ISE("Invalid midstream marker (id = %s, position = %d)", id, bytesAdded - bytesBuffered);
}
}
}
if (streamPart == StreamPart.FOOTER) {
if (bytesBuffered > 0) {
// Footer is discarded: it isn't useful when reading frame files as streams. (It contains pointers
// for random access of frames.)
deleteFromQueuedChunks(bytesBuffered);
}
assert bytesBuffered == 0 && chunks.isEmpty() && nextCompressedFrameLength == UNKNOWN_LENGTH;
}
if (addChunkBackpressureFuture != null && (bytesBuffered < bytesLimit || !canReadFrame())) {
// Release backpressure.
addChunkBackpressureFuture.set(null);
addChunkBackpressureFuture = null;View on GitHub (pinned to 9b90983fd2)