apache/druid · error · RuntimeException

Invalid frame file trailer for object :

Error message

Invalid frame file trailer for object : 

What it means

openPartitionedChannel validates each written frame file by reading its trailer (the last FrameFileWriter.TRAILER_LENGTH bytes) and throws a RuntimeException when the trailer bytes read is shorter than the expected trailer length. This means the frame file is truncated or corrupt and its metadata (frame sizes/counts) cannot be parsed.

Solutions

  1. Rerun the query so the producer rewrites the partition output file.
  2. Check the producing task logs for crash/disk-full errors and verify the file size in deep storage against the expected channel size.
  3. Check task-runner reliability (avoid killing tasks mid-write) and deep-storage upload integrity (multipart completion).
  4. Verify all Druid services run compatible MSQ versions to avoid format mismatches.

Example fix

null
Defensive patterns

Strategy: retry

Validate before calling

// sanity-check remote object size before parsing the trailer
long size = storageConnector.size(fileName);
if (size <= FrameFileWriter.TRAILER_LENGTH) {
  throw new IllegalStateException("Frame file suspiciously small/truncated: " + fileName);
}

Try / catch

try {
  readPartitionOutput();
} catch (RuntimeException e) {
  if (e.getMessage() != null && e.getMessage().contains("Invalid frame file trailer")) {
    rerunQuery(); // truncated output must be regenerated
  } else { throw e; }
}

Prevention

When it happens

Trigger: Reading the trailer of the partition output file via FileChannel.read returns fewer bytes than TRAILER_LENGTH: the file was written incompletely (producer crash/disk full), uploaded partially to deep storage, or is otherwise truncated/corrupt.

Common situations: Worker killed (OOM/preemption) while writing output; interrupted upload leaving a partial object; disk full on the task's tmp dir; version mismatch causing wrong trailer format expectations.

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


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

Appendix: source

Thrown at multi-stage-query/src/main/java/org/apache/druid/msq/shuffle/output/DurableStorageTaskOutputChannelFactory.java:184

        );

    final Supplier<Long> channelSizeSupplier = countingOutputStream::getCount;

    final File footerFile = new File(tmpDir, fileName + "_footer");
    // build supplier for reading the footer of the underlying frame file
    final Supplier<FrameFileFooter> frameFileFooterSupplier = Suppliers.memoize(() -> {
      try {
        // read trailer and find the footer size
        byte[] trailerBytes = new byte[FrameFileWriter.TRAILER_LENGTH];
        long channelSize = channelSizeSupplier.get();
        try (InputStream reader = storageConnector.readRange(
            fileName,
            channelSize - FrameFileWriter.TRAILER_LENGTH,
            FrameFileWriter.TRAILER_LENGTH
        )) {
          int bytesRead = reader.read(trailerBytes, 0, trailerBytes.length);
          if (bytesRead != FrameFileWriter.TRAILER_LENGTH) {
            throw new RuntimeException("Invalid frame file trailer for object : " + fileName);
          }
        }

        Memory trailer = Memory.wrap(trailerBytes);
        int footerLength = trailer.getInt(Integer.BYTES * 2L);

        // read the footer into a file and map it to memory
        FileUtils.mkdirp(footerFile.getParentFile());
        Preconditions.checkState(footerFile.createNewFile(), "Unable to create local footer file");
        try (FileOutputStream footerFileStream = new FileOutputStream(footerFile);
             InputStream footerInputStream =
                 storageConnector.readRange(fileName, channelSize - footerLength, footerLength)) {
          IOUtils.copy(footerInputStream, footerFileStream);
        }
        MappedByteBufferHandler mapHandle = FileUtils.map(footerFile);
        Memory footerMemory = Memory.wrap(mapHandle.get(), ByteOrder.LITTLE_ENDIAN);

        // create a frame file footer from the mapper memory

View on GitHub (pinned to 9b90983fd2)