{"record":{"id":"50ef79716d238d15","repo":"apache/druid","slug":"header-file-s-is-d-bytes-on-disk-but-its-meta","errorCode":null,"errorMessage":"Header file[%s] is [%d] bytes on disk but its metadata describes [%d] bytes (header[%d] plus bitmap[%d]); treating it as corrupt","messagePattern":"Header file\\[(.+?)\\] is \\[(.+?)\\] bytes on disk but its metadata describes \\[(.+?)\\] bytes \\(header\\[(.+?)\\] plus bitmap\\[(.+?)\\]\\); treating it as corrupt","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"critical","filePath":"processing/src/main/java/org/apache/druid/segment/file/PartialSegmentFileMapperV10.java","lineNumber":1421,"sourceCode":"    return mapUninterruptibly(() -> {\n      try (RandomAccessFile raf = new RandomAccessFile(headerFile, \"rw\");\n           FileChannel channel = raf.getChannel()) {\n        return channel.map(FileChannel.MapMode.READ_WRITE, result.getHeaderSize(), numBitmapBytes);\n      }\n    });\n  }\n\n  /**\n   * Corruption check for a header file restored from a previous session: its length must be exactly the header plus\n   * one bit per internal file, since {@link #fetchAndPersistHeader} only ever publishes both regions together.\n   */\n  private static void verifyPersistedHeaderLength(File headerFile, SegmentFileMetadataReader.Result result)\n      throws IOException\n  {\n    final long expectedSize = headerFileSize(result);\n    final long actualSize = headerFile.length();\n    if (actualSize != expectedSize) {\n      throw new IOException(\n          StringUtils.format(\n              \"Header file[%s] is [%d] bytes on disk but its metadata describes [%d] bytes (header[%d] plus \"\n              + \"bitmap[%d]); treating it as corrupt\",\n              headerFile,\n              actualSize,\n              expectedSize,\n              result.getHeaderSize(),\n              numBitmapBytes(result.getMetadata())\n          )\n      );\n    }\n  }\n\n  /**\n   * Establish a memory mapping, shielding it from the calling thread's interrupt status.\n   * <p>\n   * {@link FileChannel#map} is an interruptible channel operation: an interrupt (a canceled query, a stage tearing\n   * down, {@code shutdownNow} on the processing pool) closes the channel mid-call and surfaces as","sourceCodeStart":1403,"sourceCodeEnd":1439,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/segment/file/PartialSegmentFileMapperV10.java#L1403-L1439","documentation":"PartialSegmentFileMapperV10 validates that a header file's on-disk size exactly matches the size recorded in its metadata (header bytes plus bitmap bytes). If they differ, the header file is treated as corrupt and an IOException is thrown so the segment file will not be trusted. This protects readers from using a truncated or padded header that would misalign bitmap and metadata reads.","triggerScenarios":"Reading a segment file whose <name>.hdr companion file was truncated by a partial write, disk-full event, interrupted download, or manual copy while verifyPersistedHeaderLength computes headerFileSize(result) != headerFile.length().","commonSituations":"Segments copied between nodes with rsync/scp interrupted mid-transfer; crash during persist leaving a partial header; restoring from an incomplete backup; disk-full conditions during segment write.","solutions":["Re-download or re-copy the segment from a healthy replica so the header file matches its metadata size","Re-ingest or re-index the affected segment from source data to regenerate a complete header file","Check for disk-full or interrupted writes on the historical node's segment cache directory and clean up corrupt entries (remove the segment dir so it is re-fetched)"],"exampleFix":"// no caller code fix; recover the data\n# before: corrupt segment dir in cache\n# after: remove and re-fetch\nrm -rf /var/druid/segment-cache/<segment_id>","handlingStrategy":"validation","validationCode":"// Java: verify header file size before using the segment\nlong expected = metadata.getHeaderSize() + metadata.getBitmapSize();\nif (new File(headerPath).length() != expected) {\n  throw new IOException(\"corrupt header: \" + headerPath);\n}","typeGuard":null,"tryCatchPattern":"try {\n  openSegmentFile(segmentDir);\n} catch (IOException e) {\n  if (e.getMessage().contains(\"treating it as corrupt\")) {\n    deleteSegmentFromCache(segmentDir); // force re-fetch from deep storage\n    retryDownload(segmentId);\n  } else { throw e; }\n}","preventionTips":["Use checksumming/integrity-aware copy tools (rsync -c, s3 etag checks) when moving segments","Monitor historical segment-cache disks for full-disk conditions","Verify segment sizes after restore from backup before loading"],"tags":["segment-files","corruption","io"],"backgroundTag":"checksum-mismatch","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}