EpicGames/lore · error · io::Error (InvalidData)

level header file has invalid magic 0x

Error message

level header file has invalid magic 0x{:08x}, expected 0x{:08x}

What it means

After loading the header bytes, `read_level_header_file` validates the `magic` field against `MARKER_MAGIC`. A mismatch means the file is not a lore-storage level marker at all (wrong file placed at the marker path, corrupted contents, or a byte-shifted/truncated-then-overwritten file). It fails with `ErrorKind::InvalidData`.

Solutions

  1. Treat the store directory as corrupt: remove the invalid marker file and rebuild/re-seed the level.
  2. Verify the directory is used exclusively by this lore-storage version (no foreign files at marker paths).
  3. Restore the store from a known-good backup.

Example fix

// before
let header = read_level_marker(dir).await?;

// after
match read_level_marker(dir).await {
    Ok(h) => h,
    Err(e) if e.kind() == io::ErrorKind::InvalidData => {
        eprintln!("corrupt level marker in {dir:?}; re-initializing");
        fs::remove_file(marker_path(dir)).ok();
        None
    }
    Err(e) => return Err(e),
}
Defensive patterns

Strategy: try-catch

Validate before calling

let bytes = tokio::fs::read(&header_path).await?;
let magic = u32::from_le_bytes(bytes[..4].try_into()?);
if magic != MARKER_MAGIC { /* foreign/corrupt file: re-init */ }

Try / catch

match read_level_marker(dir).await {
    Err(e) if e.kind() == io::ErrorKind::InvalidData => {
        eprintln!("bad marker magic in {dir:?}; removing and re-initializing");
        remove_corrupt_header(dir)?;
    }
    other => other?,
}

Prevention

When it happens

Trigger: Reading a level marker/pending header whose first bytes do not equal `MARKER_MAGIC` — e.g. the path contains user data, another tool's file, or the header was overwritten.

Common situations: Hand-editing or corruption of store internals, a different lore-storage version/layout sharing the same directory, or restoring the wrong files into the store directory.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of EpicGames/lore@074eb0b0d1 (2026-09-13). Data as JSON: /api/errors/3e9049c09eed2d57. Report an issue: GitHub.

Appendix: source

Thrown at lore-storage/src/local/fan_out.rs:399

    let bytes = match lore_io::IoDriver::global().read_file_bytes(path).await {
        Ok(bytes) => bytes,
        Err(err) if err.kind() == std::io::ErrorKind::NotFound => return Ok(None),
        Err(err) => return Err(err),
    };
    let mut header = LevelMarkerHeader::new_zeroed();
    let expected = size_of::<LevelMarkerHeader>();
    if bytes.len() < expected {
        return Err(std::io::Error::new(
            std::io::ErrorKind::UnexpectedEof,
            format!(
                "level header file is {} bytes, expected {expected}",
                bytes.len()
            ),
        ));
    }
    header.as_mut_bytes().copy_from_slice(&bytes[..expected]);
    if header.magic != MARKER_MAGIC {
        return Err(std::io::Error::new(
            std::io::ErrorKind::InvalidData,
            format!(
                "level header file has invalid magic 0x{:08x}, expected 0x{:08x}",
                header.magic, MARKER_MAGIC
            ),
        ));
    }
    if header.version != MARKER_VERSION {
        return Err(std::io::Error::new(
            std::io::ErrorKind::InvalidData,
            format!(
                "level header file has unsupported version {}, expected {}",
                header.version, MARKER_VERSION
            ),
        ));
    }
    Ok(Some(header.bucket_count as usize))
}

View on GitHub (pinned to 074eb0b0d1)