vercel/next.js · error

fixed key block for entries is the wrong size

Error message

fixed key block for {entry_count} entries is the wrong size

What it means

For a fixed-layout key block, turbo-persistence computes the exact total byte length the entries region must have (FixedRegions::total_len for entry_count) and requires the block's entries slice to match exactly. A mismatch means the block's declared entry count, key size, and value size do not fit its actual bytes — i.e. the block is corrupt or was written with an incompatible layout.

Solutions

  1. Delete the persistent cache directory and rebuild.
  2. Clear the cache across Next.js/Turbopack version switches to avoid writer/reader layout mismatch.
  3. Confirm the cache directory is not concurrently written by multiple builds.
  4. Reproduce on a fresh cache and report if it persists.
Defensive patterns

Strategy: fallback

Try / catch

try {
  lookup(key);
} catch (e) {
  if (/is the wrong size/.test(String(e))) {
    resetCache();
  } else throw e;
}

Prevention

When it happens

Trigger: A fixed-key SST key block where entries.len() != regions.total_len(entry_count) during lookup_variable-style point lookup — truncated block, wrong header_type, or stale cache written by a different version.

Common situations: Version skew between cache writer and reader after upgrading Next.js/Turbopack; cache corruption after a crash mid-write.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of vercel/next.js@34433fd12e (2026-09-20). Data as JSON: /api/errors/51280f37e7109c28. Report an issue: GitHub.

Appendix: source

Thrown at turbopack/crates/turbo-persistence/src/static_sorted_file.rs:651

        &self,
        block: &[u8],
        key_hash: u64,
        key: &K,
        layout: KeyBlockLayout,
        reader: ArcBlockCacheReader<'_>,
    ) -> Result<SstLookupResult> {
        ensure!(block.len() >= 6, "fixed key block too short");
        let entry_count = be::read_u24(&block[1..]) as usize;
        let key_size = be::read_u8(&block[4..]) as usize;
        let header_type = be::read_u8(&block[5..]);
        let FixedValueLayout {
            value_type,
            val_size,
            header_size,
        } = fixed_value_layout(block, header_type)?;
        let regions = FixedRegions::new(entry_count, layout, key_size, val_size);
        let entries = &block[header_size..];
        ensure!(
            entries.len() == regions.total_len(entry_count),
            "fixed key block for {entry_count} entries is the wrong size"
        );

        self.lookup_block_inner::<K, FIND_ALL>(entry_count, key_hash, key, layout, reader, |i| {
            get_fixed_key_entry(entries, i, regions, value_type)
        })
    }

    /// Shared binary search + collection logic for both key block variants.
    ///
    /// The `get_entry` closure abstracts over the difference between variable-size
    /// key blocks (offset table lookup) and fixed-size key blocks (stride-based indexing).
    fn lookup_block_inner<'a, K: QueryKey, const FIND_ALL: bool>(
        &self,
        entry_count: usize,
        key_hash: u64,
        key: &K,

View on GitHub (pinned to 34433fd12e)