stride3d/stride · error · ContentStreamingException

Invalid storage offset.

Error message

Invalid storage offset.

What it means

ContentStorage.Create serializes chunks into a new storage stream, tracking the expected cumulative offset. After writing all chunks it compares the computed offset with outputStream.Position; a mismatch means the stream position advanced unexpectedly (chunk wrote wrong byte count or the stream is misbehaving), producing an internally inconsistent bundle.

Solutions

  1. Ensure each chunk's Write emits exactly its recorded Size bytes to the stream.
  2. Pass a dedicated, exclusive, seekable output stream to Create and don't touch it during creation.
  3. Compute chunk sizes/offsets before writing and keep them consistent with actual written bytes.

Example fix

// before
using (var shared = File.OpenWrite(path)) // also used elsewhere
    storage.Create(shared);
// after
using (var dedicated = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None))
    storage.Create(dedicated);
Defensive patterns

Strategy: try-catch

Validate before calling

// verify each chunk's declared size matches its data before Create
foreach (var c in chunks)
    if (c.Size != GetSerializedLength(c.Data))
        throw new InvalidOperationException("Chunk size mismatch before packaging");

Try / catch

try { storage.Create(outputStream); }
catch (ContentStreamingException ex) when (ex.Message == "Invalid storage offset.") {
    logger.Error("Bundle serialization desynced; discard partial output and re-create.");
    outputStream.SetLength(0);
}

Prevention

When it happens

Trigger: Writing chunks whose serialized size differs from their recorded Size; passing a non-seekable or externally advanced output stream; concurrent writes to the same stream during bundle creation.

Common situations: Custom chunk writers updating stream position outside Create; writing bundles to streams shared with other writers (e.g. a log-wrapped stream that injects bytes); bugs in custom IChunk data serialization.

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 stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/525712f22b3dea59. Report an issue: GitHub.

Appendix: source

Thrown at sources/core/Stride.Core.Serialization/Streaming/ContentStorage.cs:196

        for (int i = 0; i < chunksCount; i++)
        {
            int chunkIndex = chunksOrder[i];
            int size = chunksData[chunkIndex].Length;
            header.Chunks[chunkIndex].Location = offset;
            header.Chunks[chunkIndex].Size = size;
            offset += size;
        }

        // Create file with a raw data
        using var outputStream = contentManager.FileProvider.OpenStream(dataUrl, VirtualFileMode.Create, VirtualFileAccess.Write, VirtualFileShare.Read, StreamFlags.Seekable);
        using var stream = new BinaryWriter(outputStream);
        // Write data (one after another)
        for (int i = 0; i < chunksCount; i++)
            stream.Write(chunksData[chunksOrder[i]]);

        // Validate calculated offset
        if (offset != outputStream.Position)
            throw new ContentStreamingException("Invalid storage offset.");
    }

    /// <inheritdoc/>
    public sealed override int GetHashCode()
    {
        unchecked
        {
            int hashCode = (int)PackageTime.Ticks;
            hashCode = (hashCode * 397) ^ chunks.Length;
            for (int i = 0; i < chunks.Length; i++)
                hashCode = (hashCode * 397) ^ chunks[i].Size;
            return hashCode;
        }
    }

    /// <inheritdoc/>
    protected override void Destroy()
    {

View on GitHub (pinned to 96fad776d2)