{"record":{"id":"274eaad7cf7192fc","repo":"tursodatabase/turso","slug":"8-274eaa","errorCode":"8","errorMessage":"SQLite Error 8: 'attempt to write a readonly database'.","messagePattern":"SQLite Error 8: 'attempt to write a readonly database'\\.","errorType":"error_code","errorClass":"SqliteException","httpStatus":null,"severity":"error","filePath":"bindings/dotnet/src/Turso.Data.Sqlite/SqliteCommand.cs","lineNumber":370,"sourceCode":"            }\n        }\n    }\n\n    private async Task<SqliteDataReader> ExecuteManagedAsync(\n        string method,\n        CommandBehavior behavior,\n        CancellationToken cancellationToken)\n    {\n        EnsureExecutable(method);\n        var statements = GetManagedStatements();\n        if (Connection!.HasOpenReader && statements.Any(IsWriteStatement))\n        {\n            await Task.Delay(TimeSpan.FromSeconds(CommandTimeout), cancellationToken).ConfigureAwait(false);\n            throw new SqliteException(Properties.Resources.SqliteNativeError(5, \"database is locked\"), 5);\n        }\n        if (Connection!.IsReadOnly && statements.Any(IsWriteStatement))\n        {\n            throw new SqliteException(\n                Properties.Resources.SqliteNativeError(8, \"attempt to write a readonly database\"),\n                8);\n        }\n        if (statements.Count == 0)\n        {\n            _hasOpenReader = true;\n            Connection!.ReaderOpened();\n            return new SqliteDataReader(this, -1, behavior, CloseReader);\n        }\n\n        ValidateManagedParameterValues();\n        var results = new List<ManagedSqliteResult>();\n        var recordsAffected = 0;\n        var hadResultSet = false;\n        foreach (var statement in statements)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            if (TryHandleFacadeStatement(statement.Sql, out var sql))","sourceCodeStart":352,"sourceCodeEnd":388,"githubUrl":"https://github.com/tursodatabase/turso/blob/6c7252267988c76e632af00a671e4b9788dfae13/bindings/dotnet/src/Turso.Data.Sqlite/SqliteCommand.cs#L352-L388","documentation":"SqliteCommand's managed execution path throws a simulated SQLITE_READONLY (code 8, 'attempt to write a readonly database') when the connection was opened in read-only mode (Connection.IsReadOnly) and the statement list contains any write statement (INSERT/UPDATE/DELETE/DDL). The operation is rejected before touching the database.","triggerScenarios":"Opening the connection with Mode=ReadOnly in the connection string (or a read-only datasource) and executing INSERT/UPDATE/DELETE/CREATE/etc. via ExecuteNonQuery/ExecuteReader on a managed connection.","commonSituations":"Connection strings copied from a read-only analytics setup being reused for write endpoints; environment-specific config (prod writes allowed, CI/dataset mounted read-only); accidentally passing a read-only file path or read-only replica options.","solutions":["Reopen the connection without Mode=ReadOnly (e.g. Mode=ReadWrite or default) for write workloads","Use two connections: a read-only one for queries and a writable one for mutations","Check Connection.IsReadOnly (or the connection string) before issuing writes and route accordingly","Fix file permissions if the read-only mode was unintentional (e.g. read-only mount)"],"exampleFix":"// before\nvar conn = new SqliteConnection(\"Data Source=app.db;Mode=ReadOnly\");\nconn.Execute(\"INSERT INTO t VALUES (1)\"); // throws code 8\n// after\nvar conn = new SqliteConnection(\"Data Source=app.db;Mode=ReadWrite\");\nconn.Execute(\"INSERT INTO t VALUES (1)\");","handlingStrategy":"validation","validationCode":"if (connection.IsReadOnly && IsWriteSql(commandText))\n    throw new InvalidOperationException(\"Cannot execute write SQL on a read-only connection.\");","typeGuard":null,"tryCatchPattern":"try { cmd.ExecuteNonQuery(); }\ncatch (SqliteException ex) when (ex.SqliteErrorCode == 8)\n{\n    // reroute to writable connection\n    writableConnection.Execute(cmd.CommandText);\n}","preventionTips":["Check Mode=ReadOnly in connection strings when setting up write paths","Maintain separate read-only and writable connection factories","Catch SqliteErrorCode 8 to detect misrouted writes in tests"],"tags":["dotnet","sqlite","read-only","permission"],"backgroundTag":"permission-denied","analyzedSha":"6c7252267988c76e632af00a671e4b9788dfae13","analyzedAt":"2026-09-06T07:15:26.990Z","contentChangedAt":"2026-09-06T07:15:26.990Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}