vercel/next.js · error

key block too short

Error message

key block too short

What it means

In lookup_variable_key_block, a key block must contain at least a 4-byte header before its entry offset table can be read. This ensure! fires when the block fetched from the block cache is shorter than 4 bytes, indicating a corrupt or truncated key block.

Solutions

  1. Delete the persistent cache directory and rebuild it.
  2. Check filesystem integrity (fsck / SMART) if corruption recurs.
  3. Ensure the cache is not on a network/shared volume subject to partial writes.
  4. If reproducible, report the SST file to the Turbopack team as a corruption case.
Defensive patterns

Strategy: fallback

Try / catch

try {
  lookup(key);
} catch (e) {
  if (/key block too short/.test(String(e))) {
    resetCache(); // delete cache dir and reopen
  } else throw e;
}

Prevention

When it happens

Trigger: A variable-key SST key block read via ArcBlockCacheReader that is shorter than 4 bytes — corrupt block data in the file or block cache.

Common situations: Bit-rot or truncation in a Turbopack persistent cache file; a block-cache entry pointing at the wrong byte range after a torn 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/1ff71e5ede117182. Report an issue: GitHub.

Appendix: source

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

            Err(0) => self.index.first_block,
            Err(i) => be::read_u16(&entries[i - 1][size_of::<u64>()..]),
        }
    }

    /// Looks up a key in a key block and the value in a value block.
    ///
    /// If `FIND_ALL` is false, returns after finding the first match.
    /// If `FIND_ALL` is true, collects all entries with the same key.
    fn lookup_variable_key_block<K: QueryKey, const FIND_ALL: bool>(
        &self,
        block: &[u8],
        key_hash: u64,
        key: &K,
        layout: KeyBlockLayout,
        reader: ArcBlockCacheReader<'_>,
    ) -> Result<SstLookupResult> {
        let hash_len = layout.hash_len();
        ensure!(block.len() >= 4, "key block too short");
        let entry_count = be::read_u24(&block[1..]) as usize;
        let data = &block[4..];
        let table_len = entry_count * key_block_table_stride(hash_len);
        ensure!(
            data.len() >= table_len,
            "key block too short for {entry_count} entries"
        );
        let offsets = &data[..table_len];
        let entries = &data[table_len..];

        self.lookup_block_inner::<K, FIND_ALL>(entry_count, key_hash, key, layout, reader, |i| {
            get_key_entry(offsets, entries, entry_count, i, hash_len)
        })
    }

    /// Looks up a key in a fixed-size key block.
    ///
    /// Fixed-size key blocks store entries at predictable offsets (no offset table),

View on GitHub (pinned to 34433fd12e)