prestodb/presto · critical · PrestoException

DRUID_SEGMENT_LOAD_ERROR

DRUID_SEGMENT_LOAD_ERROR

Error message

Malformed End of Central Directory Record; does not start with %08x

What it means

EndOfCentralDirectoryRecord.read reads the fixed 22-byte EOCD structure and requires it to start with signature 0x06054b50. If the bytes located by findEndOfCentralDirectoryRecord do not begin with that signature, the record is malformed and DRUID_SEGMENT_LOAD_ERROR is thrown.

Source

Thrown at presto-druid/src/main/java/com/facebook/presto/druid/zip/EndOfCentralDirectoryRecord.java:53

    private EndOfCentralDirectoryRecord()
    {
    }

    /**
     * Read the end of central directory record from the input stream and parse {@link ZipFileData}
     * from it.
     */
    public static void read(ZipFileData zipFileData, DataInputSource dataInputSource, long offset)
            throws IOException
    {
        long position = offset;
        byte[] fixedSizeData = new byte[FIXED_DATA_SIZE];

        dataInputSource.readFully(position, fixedSizeData, 0, FIXED_DATA_SIZE);
        position += FIXED_DATA_SIZE;
        if (!ZipUtil.arrayStartsWith(fixedSizeData, ZipUtil.intToLittleEndian(SIGNATURE))) {
            throw new PrestoException(DRUID_SEGMENT_LOAD_ERROR, format("Malformed End of Central Directory Record; does not start with %08x", SIGNATURE));
        }

        byte[] comment = new byte[ZipUtil.getUnsignedShort(fixedSizeData, COMMENT_LENGTH_OFFSET)];
        if (comment.length > 0) {
            dataInputSource.readFully(position, comment, 0, comment.length);
        }
        short diskNumber = ZipUtil.get16(fixedSizeData, DISK_NUMBER_OFFSET);
        short centralDirectoryDisk = ZipUtil.get16(fixedSizeData, CD_DISK_OFFSET);
        short entriesOnDisk = ZipUtil.get16(fixedSizeData, DISK_ENTRIES_OFFSET);
        short totalEntries = ZipUtil.get16(fixedSizeData, TOTAL_ENTRIES_OFFSET);
        int centralDirectorySize = ZipUtil.get32(fixedSizeData, CD_SIZE_OFFSET);
        int centralDirectoryOffset = ZipUtil.get32(fixedSizeData, CD_OFFSET_OFFSET);
        if (diskNumber == -1 || centralDirectoryDisk == -1 || entriesOnDisk == -1
                || totalEntries == -1 || centralDirectorySize == -1 || centralDirectoryOffset == -1) {
            zipFileData.setMaybeZip64(true);
        }
        zipFileData.setComment(comment);
        zipFileData.setCentralDirectorySize(ZipUtil.getUnsignedInt(fixedSizeData, CD_SIZE_OFFSET));

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Re-upload the segment zip after verifying it with `unzip -t`.
  2. Rebuild the archive with a standard tool if it contains nonstandard comments/data known to trip scanners.
  3. Compare checksums of the stored object against the producer's to pinpoint when corruption occurred.
  4. Retry reading from a different replica if deep storage provides multiple.

Example fix

// before
var eocd = EndOfCentralDirectoryRecord.read(dataInputSource, offset);
// after: verify tail bytes before parsing
long size = dataInputSource.getSize();
checkState(size >= offset + 22, "EOCD offset %s out of range for %s", offset, dataInputSource.getId());
var eocd = EndOfCentralDirectoryRecord.read(dataInputSource, offset);
Defensive patterns

Strategy: validation

Validate before calling

if (offset + 22 > dataInputSource.getSize()) {
    throw new IllegalStateException("EOCD offset out of range: " + offset);
}

Try / catch

try {
    eocd = EndOfCentralDirectoryRecord.read(source, offset);
} catch (PrestoException e) {
    log.error("Malformed EOCD in %s at offset %s", source.getId(), offset, e);
    retryWithReplicaOrReIngest(segmentId);
}

Prevention

When it happens

Trigger: read(offset) called with an offset whose 22 bytes lack the EOCD signature — typically when a backwards scan matched a false signature inside a ZIP comment or file data, or the region was corrupted.

Common situations: Zips with file comments or embedded data containing the EOCD signature bytes causing mislocation, corruption in the final 64KB of the file, or partial downloads that cut the record in half while keeping an earlier false-positive signature.

Understand the failure class

Related errors


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/ad0ff3abacbbc20c. Report an issue: GitHub.