apache/druid · error · IllegalStateException
Corrupt frame file: frame [%,d] location out of range
Error message
Corrupt frame file: frame [%,d] location out of range
What it means
getFrameEndPosition reads a frame's end offset from the footer and bounds-checks it against the frame-data region of the file. An out-of-range value (negative or beyond the data region) means the footer's frame pointer table is corrupt, so it throws instead of returning a bogus offset.
Solutions
- Regenerate the frame file from the producing job; the pointer table cannot be trusted or reconstructed safely.
- Re-read the file from a different replica/deep-storage location if available.
- Check the storage layer (disk errors, S3 integrity) if corruption recurs.
- Validate the whole file (footer checksum, open()) before iterating frames to fail earlier with a clearer error.
Example fix
// before
long pos = footer.startByte(frameNumber); // ISE for corrupt table
// after
// open() already validates the footer checksum; prefer fully validating first
try (FrameFile.Entry entry = FrameFile.open(file, maxMmapSize)) {
long pos = entry.footer().startByte(frameNumber);
} catch (IllegalStateException e) {
regenerateFrameFile(file); // corrupt pointer table: rebuild
} Defensive patterns
Strategy: validation
Validate before calling
FrameFile.Entry entry = FrameFile.open(file, maxMmapSize); // validates footer first
FrameFileFooter footer = entry.footer();
if (frameNumber < 0 || frameNumber >= footer.getNumFrames()) {
throw new IndexOutOfBoundsException("frameNumber=" + frameNumber);
} Type guard
static boolean isValidFrameIndex(FrameFileFooter footer, int frameNumber) {
return frameNumber >= 0 && frameNumber < footer.getNumFrames();
} Try / catch
try {
long end = footer.endByte(frameNumber);
} catch (IllegalStateException e) {
if (e.getMessage().contains("location out of range")) {
// corrupt pointer table: switch to a replica or regenerate
throw new IllegalStateException("Frame pointers corrupt: " + file, e);
}
throw e;
} Prevention
- Always open/validate the whole frame file before random frame access.
- Keep frame indices within [0, numFrames).
- Verify file integrity from deep storage if out-of-range errors appear.
- Maintain single-writer, publish-after-complete output discipline.
When it happens
Trigger: Calling getFrameEndPosition (directly or via startByte/endByte) on a frame file whose footer frame-end table was corrupted, truncated, or written inconsistently — the stored long is negative or exceeds fileLength - footerSize.
Common situations: Reading a frame file damaged by a partial write or crash; accessing a specific frame index in a file that failed footer validation edge cases; disk corruption on deep storage.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- Expected footer checksum did not match actual checksum…
- Expected footer length did not match actual footer length…
- File [ ] end marker not in expected location
- File[ ] is too short (size[%,d])
- Negative-size footer. Corrupt or truncated file
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/d014d95962ec368d.
Report an issue: GitHub.
Appendix: source
Thrown at processing/src/main/java/org/apache/druid/frame/file/FrameFileFooter.java:112
}
/**
* Get the last byte for the frame specified. The byte number is offsetted from the frame file start and is exclusive.
* @param frameNumber the id of the frame to get the end position for
* @return a long exclusive index representing the frame end
*/
public long getFrameEndPosition(final int frameNumber)
{
assert frameNumber >= 0 && frameNumber < numFrames;
final long frameEndPointerPosition =
footerMemory.getCapacity() - FrameFileWriter.TRAILER_LENGTH - (long) (numFrames - frameNumber) * Long.BYTES;
final long frameEndPosition = footerMemory.getLong(frameEndPointerPosition);
// Bounds check: protect against possibly-corrupt data.
if (frameEndPosition < 0 || frameEndPosition > frameFileLength - footerMemory.getCapacity()) {
throw new ISE("Corrupt frame file: frame [%,d] location out of range", frameNumber);
}
return frameEndPosition;
}
public int getNumFrames()
{
return numFrames;
}
public int getNumPartitions()
{
return numPartitions;
}
}
View on GitHub (pinned to 9b90983fd2)