{"record":{"id":"dacff729d03c91a2","repo":"stride3d/stride","slug":"read-only-backend","errorCode":null,"errorMessage":"Read-only backend.","messagePattern":"Read-only backend\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/core/Stride.Core.Serialization/Storage/FileOdbBackend.cs","lineNumber":132,"sourceCode":"\n        if (!forceWrite && virtualFileProvider.FileExists(url))\n            return objectId;\n\n        using (var file = virtualFileProvider.OpenStream(tmpFileName, VirtualFileMode.Create, VirtualFileAccess.Write))\n        {\n            dataStream.CopyTo(file);\n        }\n\n        MoveToDatabase(tmpFileName, objectId, forceWrite);\n\n        return objectId;\n    }\n\n    /// <inheritdoc/>\n    public OdbStreamWriter CreateStream()\n    {\n        if (IsReadOnly)\n            throw new InvalidOperationException(\"Read-only backend.\");\n\n        string tmpFileName = vfsTempUrl + Guid.NewGuid() + \".tmp\";\n        Stream stream = virtualFileProvider.OpenStream(tmpFileName, VirtualFileMode.Create, VirtualFileAccess.Write);\n        return new DigestStream(stream, tmpFileName) { Disposed = x => MoveToDatabase(x.TemporaryName, x.CurrentHash) };\n    }\n\n    private void MoveToDatabase(string temporaryFilePath, ObjectId objId, bool forceWrite = false)\n    {\n        string fileUrl = BuildUrl(vfsRootUrl, objId);\n\n        lock (LockOnMove)\n        {\n            var fileExists = virtualFileProvider.FileExists(fileUrl);\n\n            // File may already exists, in this case we decide to not override it.\n            if (!fileExists || forceWrite)\n            {\n                try","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/core/Stride.Core.Serialization/Storage/FileOdbBackend.cs#L114-L150","documentation":"FileOdbBackend.CreateStream writes new objects to the database by creating a temp file and moving it into the store on dispose. When the backend was opened read-only (IsReadOnly), any write attempt throws InvalidOperationException 'Read-only backend.'.","triggerScenarios":"Calling CreateStream on a FileOdbBackend constructed/mounted with IsReadOnly set — e.g. shipped game data opened read-only, then code (or an asset import path) tries to store new objects.","commonSituations":"Running a game built with read-only data mounts while an in-game importer/editor feature attempts to save; writing to installed Program Files or read-only media; forgetting to open a writable backend in tooling.","solutions":["Open the object database backend writable (IsReadOnly = false) wherever writes are needed, e.g. in editor/user-data storage.","Route writes to a separate writable backend (e.g. a user-profile store) instead of the read-only game-data backend.","Check IsReadOnly before calling CreateStream and disable or redirect the write path in shipped builds."],"exampleFix":"// before\nusing var writer = readOnlyBackend.CreateStream(); // throws\n// after\nif (backend.IsReadOnly)\n    backend = new FileOdbBackend(writableProvider, writablePath, isReadOnly: false);\nusing var writer = backend.CreateStream();","handlingStrategy":"validation","validationCode":"if (backend.IsReadOnly)\n    throw new InvalidOperationException(\"Cannot create streams on a read-only object database backend.\");\nusing var writer = backend.CreateStream();","typeGuard":null,"tryCatchPattern":"try\n{\n    using var writer = backend.CreateStream();\n    // write object...\n}\ncatch (InvalidOperationException ex) when (ex.Message == \"Read-only backend.\")\n{\n    backend = OpenWritableBackend(); // switch to a writable store\n}","preventionTips":["Mount a writable backend (user data) for any runtime writes; keep shipped data read-only.","Check IsReadOnly before entering write paths and disable write features accordingly.","Never attempt writes to installed/read-only media; store user content in a profile directory."],"tags":["read-only","object-database","invalid-state"],"backgroundTag":"operation-not-supported","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}