apache/druid · error · IOException

File[ ] is not a frame file

Error message

File[%s] is not a frame file

What it means

FrameFile.open validates that the target file begins with the FrameFileWriter magic bytes before reading any structure. If the first MAGIC.length bytes do not match, the file was not produced by the frame file writer (or its header was overwritten/truncated). The library throws this immediately to fail fast on non-frame input.

Solutions

  1. Verify the file path points to an actual frame file produced by FrameFileWriter (check the writer job output).
  2. Check the file size — a valid frame file must be at least TRAILER_LENGTH + header bytes; re-run the producing job if it is 0 or tiny.
  3. If the file should be a frame file, re-generate it; corruption of the header is not recoverable.
  4. Add a file-format/extension sanity check before opening files from user-supplied paths.

Example fix

// before
FrameFile.open(new File("output.json"), maxMmapSize);
// after
File f = new File("output.frame");
if (f.length() < FrameFileWriter.TRAILER_LENGTH + FrameFileWriter.MAGIC.length) {
  throw new IllegalStateException("Not a frame file (too small): " + f);
}
FrameFile.open(f, maxMmapSize);
Defensive patterns

Strategy: validation

Validate before calling

if (file == null || file.length() < FrameFileWriter.TRAILER_LENGTH) {
  throw new IllegalArgumentException("Not a frame file (missing header/trailer): " + file);
}

Type guard

static boolean looksLikeFrameFile(File f) {
  return f.isFile() && f.length() >= FrameFileWriter.TRAILER_LENGTH;
}

Try / catch

try {
  FrameFile.open(file, maxMmapSize);
} catch (IOException e) {
  // includes 'is not a frame file': regenerate or re-point to correct output
  throw new UncheckedIOException("Invalid frame file: " + file, e);
}

Prevention

When it happens

Trigger: Calling FrameFile.open on a file that is empty, is a different file format, was truncated so the header bytes are missing, or whose leading bytes were modified after writing.

Common situations: Pointing a segment/frame reader at a log, JSON, or partially-written file; a job crashed mid-write leaving a zero-byte file; copying files with truncation; confusing two similarly-named output files.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/b305fdd14693c925. Report an issue: GitHub.

Appendix: source

Thrown at processing/src/main/java/org/apache/druid/frame/file/FrameFile.java:207

    // Integer.MAX_VALUE) or entire file (if file size is smaller than, or equal to, Integer.MAX_VALUE).
    Closeable sharedMapCloser = null;

    try (final RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r")) {
      final long fileLength = randomAccessFile.length();

      // Verify minimum file length.
      if (fileLength <
          FrameFileWriter.MAGIC.length + FrameFileWriter.TRAILER_LENGTH + Byte.BYTES /* MARKER_NO_MORE_FRAMES */) {
        throw new IOE("File[%s] is too short (size[%,d])", file, fileLength);
      }

      // Verify magic.
      final byte[] buf = new byte[FrameFileWriter.TRAILER_LENGTH /* Larger than FrameFileWriter.MAGIC */];
      final Memory bufMemory = Memory.wrap(buf, ByteOrder.LITTLE_ENDIAN);
      randomAccessFile.readFully(buf, 0, FrameFileWriter.MAGIC.length);

      if (!bufMemory.equalTo(0, Memory.wrap(FrameFileWriter.MAGIC), 0, FrameFileWriter.MAGIC.length)) {
        throw new IOE("File[%s] is not a frame file", file);
      }

      // Read number of frames and partitions.
      randomAccessFile.seek(fileLength - FrameFileWriter.TRAILER_LENGTH);
      randomAccessFile.readFully(buf, 0, FrameFileWriter.TRAILER_LENGTH);

      final int footerLength = bufMemory.getInt(Integer.BYTES * 2L);
      if (footerLength < 0) {
        throw new ISE("Negative-size footer. Corrupt or truncated file[%s]?", file);
      } else if (footerLength > fileLength) {
        throw new ISE("Oversize footer. Corrupt or truncated file[%s]?", file);
      }

      final Memory wholeFileMemory;
      final Memory footerMemory;

      if (fileLength <= maxMmapSize) {
        // Map entire file, use region for footer.

View on GitHub (pinned to 9b90983fd2)