facebook/flow · error · std::io::Error
hh_load_heap: invalid magic number
Error message
hh_load_heap: invalid magic number
What it means
A serialized Flow heap starts with a SerializedHeapHeader whose magic number pins the exact binary format. read_heap_with_file_table accepts only the two magics this build understands (RUST_SHARDED_LOCAL_INDEXED_LZ4 and the EXTERNAL_FILES variant); any other leading bytes return ErrorKind::InvalidData "hh_load_heap: invalid magic number". The file is not a heap this build can read — wrong format, wrong version, or not a heap at all.
Source
Thrown at rust_port/crates/flow_heap/src/transaction.rs:1266
self.stage_heap_replacement(data);
Ok(())
}
pub(crate) fn read_heap(reader: &mut impl Read) -> std::io::Result<CommittedHeapData> {
let header: SerializedHeapHeader = decode_from_reader(reader)?;
Self::validate_serialized_heap_header(&header, HEAP_MAGIC_RUST_SHARDED_LOCAL_INDEXED_LZ4)?;
Self::read_heap_shards(reader, None)
}
pub(crate) fn read_heap_with_file_table(
reader: &mut impl Read,
files: Arc<Vec<FileKey>>,
) -> std::io::Result<CommittedHeapData> {
let header: SerializedHeapHeader = decode_from_reader(reader)?;
if header.magic != HEAP_MAGIC_RUST_SHARDED_LOCAL_INDEXED_LZ4
&& header.magic != HEAP_MAGIC_RUST_SHARDED_INDEXED_LZ4_EXTERNAL_FILES
{
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"hh_load_heap: invalid magic number",
));
}
if header.file_shard_count != GC_MAP_SHARDS as u64
|| header.haste_module_shard_count != GC_MAP_SHARDS as u64
{
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"hh_load_heap: invalid shard count",
));
}
let files = if header.magic == HEAP_MAGIC_RUST_SHARDED_INDEXED_LZ4_EXTERNAL_FILES {
Some(files)
} else {
None
};
Self::read_heap_shards(reader, files)View on GitHub (pinned to f88ac94bcf)
Solutions
- Delete the offending heap/saved-state file and let Flow regenerate it from sources.
- Confirm the reader and writer are the same Flow build — mixed versions in PATH or CI caches are the usual cause.
- Check the file size and first bytes: a 0-byte or text file where a heap is expected means the path is wrong.
Example fix
# before: heap written by an older/newer build -> invalid magic number flow check # after: remove mismatched saved state and rebuild rm -rf .flow-saved-state # or your configured saved-state directory flow check
Defensive patterns
Strategy: fallback
Type guard
fn is_invalid_heap_magic(e: &std::io::Error) -> bool {
e.kind() == std::io::ErrorKind::InvalidData && e.to_string().contains("invalid magic number")
} Try / catch
On InvalidData 'invalid magic number', fall back to a cold start: delete/regenerate the saved heap and rebuild. Log which file failed so operators can spot version-skew patterns across a fleet.
Prevention
- Key saved-state paths by Flow version and heap format.
- Write-then-rename when persisting heaps so readers never see partial files.
- Fail fast on 0-byte heap files before attempting to parse them.
When it happens
Trigger: Pointing hh_load_heap/read_heap at a file that is not a saved heap (random/text file passed where a heap is expected), a truncated file whose header is garbage, or a heap written by a build whose format magic differs from the reader's.
Common situations: Reusing saved-state files across Flow versions that changed the heap format; a zero-byte heap left by a crashed first save; copied/moved artifacts whose names match but contents do not.
Related errors
- invalid file index
- hh_load_heap: invalid shard count
- Can't decode daemon parameters: {}
- failed to decompress
- failed to deserialize AST
AI-assisted analysis of facebook/flow@f88ac94bcf (2026-08-20).
Data as JSON: /api/errors/39389be76e14073b.
Report an issue: GitHub.