stride3d/stride · error · InvalidOperationException
Read-only object database.
Error message
Read-only object database.
What it means
ObjectDatabase.Delete removes an object by id from the write backend. If the database was constructed without a write backend (backendWrite == null), it is read-only and any mutation — including Delete — throws. This is a deliberate guard so read-only mounts (e.g. bundled assets) are never modified.
Solutions
- Open the ObjectDatabase with a writable backend (backendWrite) before deleting.
- Only call Delete in tooling/editor contexts where a write backend exists.
- Check for a public writable/readonly indicator before mutating and handle read-only cases gracefully.
Example fix
// before
objDatabase.Delete(objectId);
// after
if (objDatabase.backendWrite != null) // or use a public IsReadOnly accessor if available
objDatabase.Delete(objectId);
else
logger.Warn("Object database is read-only; skipping delete"); Defensive patterns
Strategy: validation
Validate before calling
if (database.backendWrite == null)
return; // skip mutation on read-only database Try / catch
try { database.Delete(objectId); }
catch (InvalidOperationException ex) when (ex.Message.Contains("Read-only object database")) {
logger.Warn($"Skipping delete of {objectId}: database is read-only");
} Prevention
- Know your database mount mode (read-only bundles vs writable store)
- Perform deletions in editor/tooling contexts only
- Centralize mutations behind a helper that checks writability first
When it happens
Trigger: Calling ObjectDatabase.Delete(objectId) on an ObjectDatabase created/opened without a writable IOdbBackend.
Common situations: Deleting cached assets at runtime when the database only has a bundle/read backend; cleanup code running against a read-only APK/asset mount; connecting to the store with read-only flags.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Read-only backend.
- Can't pack files.
- Unable to find a serializer for
- Unable to find a serializer for the specified asset. No…
- Unable to find a serializer for
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/22e4de6e82e3a520.
Report an issue: GitHub.
Appendix: source
Thrown at sources/core/Stride.Core.Serialization/Storage/ObjectDatabase.cs:218
if (BundleBackend != null)
result = result.Union(BundleBackend.EnumerateObjects());
if (backendRead2 != null)
result = result.Union(backendRead2.EnumerateObjects());
return result;
}
public IEnumerable<ObjectId> EnumerateLooseObjects()
{
return backendRead1.EnumerateObjects();
}
public void Delete(ObjectId objectId)
{
if (backendWrite == null)
throw new InvalidOperationException("Read-only object database.");
backendWrite.Delete(objectId);
}
/// <summary>
/// Refreshes an object's last-use time for mtime-LRU GC and records it in the session working set
/// (see <see cref="RetouchWorkingSet"/>). Best-effort and throttled; only the writable loose-file
/// store supports it (bundles/read-only backends are skipped).
/// </summary>
public void Touch(ObjectId objectId)
{
touchedObjectIds.TryAdd(objectId, 0);
(backendWrite as FileOdbBackend)?.Touch(objectId);
}
/// <summary>
/// Re-touches every object hit this session so the working set doesn't age out of the mtime-LRU
/// cache while the editor sits idle (no rebuilds to touch it on-hit). Throttled per file.View on GitHub (pinned to 96fad776d2)