{"record":{"id":"d582d46179f83356","repo":"tursodatabase/turso","slug":"1","errorCode":"1","errorMessage":"SQLite Error 1: 'no such rowid: {rowId}'.","messagePattern":"SQLite Error 1: 'no such rowid: (.+?)'\\.","errorType":"exception","errorClass":"SqliteException","httpStatus":null,"severity":"error","filePath":"bindings/dotnet/src/Turso.Data.Sqlite/SqliteBlob.cs","lineNumber":145,"sourceCode":"\n        using var command = _connection.CreateCommand();\n        command.CommandText = \"UPDATE \" + QuoteIdentifier(_tableName) + \" SET \" + QuoteIdentifier(_columnName) + \" = $value WHERE rowid = $rowid;\";\n        command.Parameters.Add(\"$value\", SqliteType.Blob).Value = GetStream().ToArray();\n        command.Parameters.Add(\"$rowid\", SqliteType.Integer).Value = _rowId;\n        command.ExecuteNonQuery();\n    }\n\n    private static byte[] GetBlobValue(SqliteConnection connection, string tableName, string columnName, long rowId)\n    {\n        using var command = connection.CreateCommand();\n        command.CommandText = \"SELECT \" + QuoteIdentifier(columnName) + \" FROM \" + QuoteIdentifier(tableName) + \" WHERE rowid = $rowid;\";\n        command.Parameters.Add(\"$rowid\", SqliteType.Integer).Value = rowId;\n        var value = command.ExecuteScalar();\n        return value switch\n        {\n            byte[] bytes => bytes,\n            string text => Encoding.UTF8.GetBytes(text),\n            null or DBNull => throw new SqliteException(Properties.Resources.SqliteNativeError(1, \"no such rowid: \" + rowId), 1),\n            _ => Encoding.UTF8.GetBytes(Convert.ToString(value, System.Globalization.CultureInfo.InvariantCulture) ?? string.Empty)\n        };\n    }\n\n    private static void ValidateBuffer(byte[] buffer, int offset, int count)\n    {\n        ArgumentNullException.ThrowIfNull(buffer);\n        if (offset < 0)\n            throw new ArgumentOutOfRangeException(nameof(offset), offset, message: null);\n        if (count < 0)\n            throw new ArgumentOutOfRangeException(nameof(count), count, message: null);\n        if (offset > buffer.Length || count > buffer.Length - offset)\n            throw new ArgumentException(Properties.Resources.InvalidOffsetAndCount);\n    }\n\n    private static string QuoteIdentifier(string identifier)\n        => \"\\\"\" + identifier.Replace(\"\\\"\", \"\\\"\\\"\", StringComparison.Ordinal) + \"\\\"\";\n}","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/tursodatabase/turso/blob/bad083fafbefdeae9a42ec19bdaaad8918dcf411/bindings/dotnet/src/Turso.Data.Sqlite/SqliteBlob.cs#L127-L163","documentation":"Thrown by SqliteBlob when the backing row cannot be found. GetBlobValue runs `SELECT <col> FROM <table> WHERE rowid = $rowid`; a NULL/DBNull result means no row with that rowid exists, so the binding raises SqliteException with native error code 1 and message \"no such rowid: <rowId>\". It mirrors Microsoft.Data.Sqlite, where opening or using a blob stream against a missing row fails.","triggerScenarios":"Constructing `new SqliteBlob(connection, tableName, columnName, rowId)` or reading/writing an already-open SqliteBlob after the row was DELETEd, after a delete+reinsert made the saved rowid stale, or from another connection that removed the row while the blob stream was open. Also triggered by passing a rowid of 0, a rowid from a different table, or a rowid against a WITHOUT ROWID table.","commonSituations":"Holding a long-lived SqliteBlob stream across DML that rewrites rows; caching rowids from a previous transaction or session; concurrent writers under WAL/MVCC removing rows; code ported from a path where the row was guaranteed to exist.","solutions":["Re-read the rowid immediately before opening the blob (SELECT ... WHERE ..., last_insert_rowid(), or INSERT ... RETURNING) instead of using a cached rowid","Verify the row still exists with a cheap `SELECT 1 FROM <table> WHERE rowid = $id` before constructing SqliteBlob","Close all SqliteBlob streams before deleting or reinserting rows in the same table","Wrap blob usage in try/catch for SqliteException with SqliteErrorCode == 1 and treat it as a concurrent modification: re-fetch the rowid and retry once"],"exampleFix":"// before\nvar blob = new SqliteBlob(conn, \"files\", \"data\", rowId); // rowId captured earlier\nvar buf = new byte[blob.Length];\nblob.Read(buf, 0, buf.Length);\n\n// after\nusing var check = conn.CreateCommand();\ncheck.CommandText = \"SELECT 1 FROM files WHERE rowid = $id\";\ncheck.Parameters.Add(\"$id\", SqliteType.Integer).Value = rowId;\nif (check.ExecuteScalar() is null)\n    throw new InvalidOperationException($\"row {rowId} no longer exists; re-fetch rowid\");\nusing var blob = new SqliteBlob(conn, \"files\", \"data\", rowId);","handlingStrategy":"try-catch","validationCode":"using var cmd = conn.CreateCommand();\ncmd.CommandText = \"SELECT 1 FROM \" + table + \" WHERE rowid = $id\";\ncmd.Parameters.Add(\"$id\", SqliteType.Integer).Value = rowId;\nbool rowExists = cmd.ExecuteScalar() is not null;","typeGuard":null,"tryCatchPattern":"try\n{\n    using var blob = new SqliteBlob(conn, table, column, rowId);\n    // ... read/write\n}\ncatch (SqliteException ex) when (ex.SqliteErrorCode == 1 && ex.Message.Contains(\"no such rowid\"))\n{\n    // row vanished (deleted/rewritten concurrently): re-fetch rowid and retry once, or fail with context\n    rowId = FetchFreshRowid(conn, table, key);\n}","preventionTips":["Never cache rowids across transactions; fetch the rowid in the same transaction that opens the blob","Close all SqliteBlob streams before DELETE/INSERT that could reuse rowids in the target table","Use INSERT ... RETURNING or last_insert_rowid() to obtain rowids atomically","Treat SqliteErrorCode 1 with 'no such rowid' as a concurrent-modification signal, not a corrupt state"],"tags":["csharp","dotnet","blob","rowid","concurrency","stale-reference"],"backgroundTag":"stale-row-reference","analyzedSha":"bad083fafbefdeae9a42ec19bdaaad8918dcf411","analyzedAt":"2026-08-16T23:12:11.798Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}