copy/v86 · error · StateLoadError

Length doesn't match header: real=... header=...

Error message

Length doesn't match header: real=... header=...

What it means

The header records STATE_INDEX_TOTAL_LEN, the exact byte length the dump had when written. When check_length is true, read_state_header compares it with the actual buffer length and throws StateLoadError('Length doesn't match header: real=N header=M') on any mismatch, catching truncated, padded, or concatenated state buffers.

Source

Thrown at src/state.js:229

        }

        const header_block = new Int32Array(state.buffer, state.byteOffset, 4);

        if(header_block[STATE_INDEX_MAGIC] !== STATE_MAGIC)
        {
            throw new StateLoadError("Invalid header: " + h(header_block[STATE_INDEX_MAGIC] >>> 0));
        }

        if(header_block[STATE_INDEX_VERSION] !== STATE_VERSION)
        {
            throw new StateLoadError(
                    "Version mismatch: dump=" + header_block[STATE_INDEX_VERSION] +
                    " we=" + STATE_VERSION);
        }

        if(check_length && header_block[STATE_INDEX_TOTAL_LEN] !== len)
        {
            throw new StateLoadError(
                    "Length doesn't match header: " +
                    "real=" + len + " header=" + header_block[STATE_INDEX_TOTAL_LEN]);
        }

        return header_block[STATE_INDEX_INFO_LEN];
    }

    function read_info_block(info_block_buffer)
    {
        const info_block = new TextDecoder().decode(info_block_buffer);
        return JSON.parse(info_block);
    }

    if(new Uint32Array(state.buffer, 0, 1)[0] === ZSTD_MAGIC)
    {
        const ctx = cpu.zstd_create_ctx(state.length);

        new Uint8Array(cpu.wasm_memory.buffer, cpu.zstd_get_src_ptr(ctx) >>> 0, state.length).set(state);

View on GitHub (pinned to 180830d539)

Solutions

  1. Verify the state file size matches what was originally saved (compare with the header value printed in the error)
  2. Re-download/re-export the state file completely and retry
  3. If the state is embedded in a larger blob, slice exactly the header-reported length
  4. Check the storage/transfer path for corruption (compare checksums before and after)

Example fix

// before
emulator.restore_state(bigBlob.subarray(offset)); // length may not match header
// after
const headerLen = new Int32Array(bigBlob.buffer, bigBlob.byteOffset, 4)[3];
emulator.restore_state(bigBlob.subarray(offset, offset + headerLen));
Defensive patterns

Strategy: validation

Validate before calling

function headerLengthMatches(buf) {
    if (!(buf instanceof Uint8Array) || buf.byteLength < 12) return false;
    const h = new Int32Array(buf.buffer, buf.byteOffset, 4);
    return h[3] === buf.byteLength; // STATE_INDEX_TOTAL_LEN === len
}
if (!headerLengthMatches(state)) throw new Error("state file size mismatch");

Try / catch

try {
    emulator.restore_state(state);
} catch (e) {
    if (e instanceof StateLoadError && /Length doesn't match header/.test(e.message)) {
    reacquireStateFile(); // re-download / re-export
    } else throw e;
}

Prevention

When it happens

Trigger: Passing a Uint8Array to restore_state whose byteLength differs from the value stored at STATE_INDEX_TOTAL_LEN in the dump header — truncated download, extra bytes appended, slicing the wrong range out of a bigger blob, or byte-level corruption of the header.

Common situations: Interrupted downloads/partial uploads of state files; storage layers (localStorage, IndexedDB) altering or clipping blobs; manually slicing states out of a combined file with off-by-N errors.

Related errors


AI-assisted analysis of copy/v86@180830d539 (2026-08-31). Data as JSON: /api/errors/43bb142d5b794827. Report an issue: GitHub.