stride3d/stride · error · InvalidOperationException
Destroying a blob not created through…
Error message
Destroying a blob not created through ObjectDatabase.CreateBlob.
What it means
DestroyBlob removes a blob from the LoadedBlobs cache and is only valid for blobs produced by ObjectDatabase.CreateBlob. If the blob's ObjectId is not present in the cache, the blob was created elsewhere (or already destroyed), so the throw guards against double-free/foreign-blob disposal of unmanaged memory.
Solutions
- Only destroy blobs obtained from ObjectDatabase.CreateBlob on the same ObjectDatabase instance.
- Ensure destruction is idempotent — check/dispose once (guard with a flag or null out references).
- Use Blob.Dispose rather than DestroyBlob for blobs you did not create via CreateBlob.
Example fix
// before var blob = new Blob(objectId, data); // manually created ObjectDatabase.DestroyBlob(blob); // after var blob = ObjectDatabase.CreateBlob(stream); // created through the API ObjectDatabase.DestroyBlob(blob);
Defensive patterns
Strategy: try-catch
Type guard
static bool CanDestroy(Blob blob) =>
ObjectDatabase.LoadedBlobs != null && blob != null && ObjectDatabase.LoadedBlobs.ContainsKey(blob.ObjectId); Try / catch
try { ObjectDatabase.DestroyBlob(blob); }
catch (InvalidOperationException ex) when (ex.Message.Contains("Destroying a blob not created")) {
// blob was foreign or already destroyed; fall back to Dispose
blob?.Dispose();
} Prevention
- Only destroy blobs returned by CreateBlob from the same ObjectDatabase instance
- Make blob teardown idempotent (null references after destruction)
- Prefer Blob.Dispose for general cleanup
When it happens
Trigger: Calling ObjectDatabase.DestroyBlob on a manually constructed Blob (not from CreateBlob), or calling it twice on the same blob (second call finds it already removed).
Common situations: Custom asset loaders creating Blobs by hand then disposing via DestroyBlob; lifecycle bugs where blob destruction runs twice (e.g. both Dispose and finalizer path); blobs loaded from a different ObjectDatabase instance than the one destroying them (separate LoadedBlobs cache).
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
- Aliases are not supported in JSON
- At least one profile must be specified.
- Attributes can not be null
- Can't deduce data serializer type for generic types.
- Can't find a type with alias
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/74170def00b98c27.
Report an issue: GitHub.
Appendix: source
Thrown at sources/core/Stride.Core.Serialization/Storage/ObjectDatabase.cs:474
// Dispose the previously opened stream.
stream.Dispose();
}
// Lookup adds a reference
blob.AddReference();
}
return blob;
}
internal static void DestroyBlob(Blob blob)
{
// Remove blob from cache when destroyed
lock (LoadedBlobs)
{
if (!LoadedBlobs.Remove(blob.ObjectId))
throw new InvalidOperationException("Destroying a blob not created through ObjectDatabase.CreateBlob.");
}
}
private Stream OpenStreamForRead(ObjectId objectId, VirtualFileMode mode, VirtualFileAccess access, VirtualFileShare share)
{
if (BundleBackend?.Exists(objectId) == true)
return BundleBackend.OpenStream(objectId, mode, access, share);
if (backendRead1.Exists(objectId))
return backendRead1.OpenStream(objectId, mode, access, share);
if (backendRead2?.Exists(objectId) == true)
return backendRead2.OpenStream(objectId, mode, access, share);
throw new FileNotFoundException();
}
}
View on GitHub (pinned to 96fad776d2)