stride3d/stride · error · InvalidOperationException

No active stream.

Error message

No active stream.

What it means

Store<T> persists key/value mappings into an index stream that must first be attached (typically via Open/constructor binding). SaveValues is the internal writer used by AddValues/Save; if the underlying stream is null there is nothing to write to, so it throws InvalidOperationException.

Solutions

  1. Open/initialize the Store (attach its stream) before calling AddValues/Save
  2. Ensure Close/Dispose is not called before all pending AddValues calls complete
  3. Wrap store lifecycle in using/try-finally so usage never outlives the stream

Example fix

// before
var store = new Store<string, ObjectId>(...);
store.AddValue("url", id);
// after
var store = new Store<string, ObjectId>(...);
store.Open();
store.AddValue("url", id);
Defensive patterns

Strategy: validation

Validate before calling

if (storeIsOpen) // e.g. track via your own flag after Open()
    store.AddValues(values);
else
    throw new InvalidOperationException("Store must be opened before AddValues");

Try / catch

try { store.AddValues(values); }
catch (InvalidOperationException ex) when (ex.Message == "No active stream.")
{
    // open store and retry, or fail startup
}

Prevention

When it happens

Trigger: Calling AddValues(...) or otherwise triggering SaveValues before the store was opened/bound to a stream, or after Close() disposed the stream.

Common situations: Using a Store instance constructed manually without opening it; calling Save-related methods after disposing; failure to check that the database file was successfully opened at startup.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/00fc84db427126c1. Report an issue: GitHub.

Appendix: source

Thrown at sources/core/Stride.Core.Serialization/IO/Store.cs:155

                // Use unsavedIdMap so that loadedIdMap is still coherent before flushed to disk asynchronously (since other processes/threads might write to it as well).
                AddUnsaved(item, currentTransaction);

                if (shouldSaveValue)
                    SaveValue(item, currentTransaction);
            }
        }
        finally
        {
            if (shouldSaveValue)
                Monitor.Exit(stream);
        }
    }

    private void SaveValues(IEnumerable<T> values, int currentTransaction)
    {
        if (stream == null)
            throw new InvalidOperationException("No active stream.");

        lock (stream)
        {
            var indexStreamPosition = stream.Position;

            // Acquire lock on end of file (for appending)
            // This will prevent another thread from writing at the same time, or reading before it is flushed.
            if (LockEnabled && stream is FileStream fileStream)
            {
                LockFile(fileStream, indexStreamPosition, long.MaxValue - indexStreamPosition, true);
            }

            try
            {
                // Make sure we read up entries up to end of file (or skip it if AutoLoadNewValues is not set)
                if (AutoLoadNewValues)
                    RefreshData(stream.Length);
                else

View on GitHub (pinned to 96fad776d2)