{"record":{"id":"4ce15fae190ed5d9","repo":"tursodatabase/turso","slug":"no-current-row-call-read-before-accessing-values","errorCode":null,"errorMessage":"No current row. Call Read before accessing values.","messagePattern":"No current row\\. Call Read before accessing values\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"bindings/dotnet/src/Turso.Data/TursoRemoteDataReader.cs","lineNumber":309,"sourceCode":"\n    private RemoteStatementResult CurrentResult\n    {\n        get\n        {\n            if (_results.Count == 0)\n                throw new InvalidOperationException(\"The data reader has no result sets.\");\n\n            return _results[_resultIndex];\n        }\n    }\n\n    private bool HasCurrentRow => _rowIndex >= 0 && _rowIndex < CurrentResult.Rows.Count;\n\n    private RemoteResponseValue CurrentValue(int ordinal)\n    {\n        EnsureOpen();\n        if (!HasCurrentRow)\n            throw new InvalidOperationException(\"No current row. Call Read before accessing values.\");\n\n        ValidateOrdinal(ordinal);\n        var row = CurrentResult.Rows[_rowIndex];\n        if (ordinal >= row.Count)\n            throw new IndexOutOfRangeException($\"column ordinal {ordinal} is out of range\");\n\n        return row[ordinal];\n    }\n\n    private static long CopyArray<T>(T[] source, long dataOffset, T[]? buffer, int bufferOffset, int length)\n    {\n        ArgumentOutOfRangeException.ThrowIfNegative(dataOffset);\n        ArgumentOutOfRangeException.ThrowIfNegative(bufferOffset);\n        ArgumentOutOfRangeException.ThrowIfNegative(length);\n\n        if (dataOffset >= source.LongLength)\n            return 0;\n","sourceCodeStart":291,"sourceCodeEnd":327,"githubUrl":"https://github.com/tursodatabase/turso/blob/6c7252267988c76e632af00a671e4b9788dfae13/bindings/dotnet/src/Turso.Data/TursoRemoteDataReader.cs#L291-L327","documentation":"The reader starts at row index -1 and only Read() advances it; CurrentValue (backing every GetX, GetValue, the indexers, and IsDBNull) throws InvalidOperationException whenever the index is outside the current result's rows. That covers both before-first-Read and after-Read-returned-false positions, including after NextResult() reset the index.","triggerScenarios":"Calling any value accessor without calling Read() first; continuing to access values after Read() returned false; calling NextResult() and then reading values without calling Read() again on the new set; assuming HasRows == true implies a current row.","commonSituations":"Classic ADO.NET misuse in freshly written data access code; helper that does reader[0] for a known-single-row query assuming implicit positioning; early-exit loops that break out of Read() and then log the row.","solutions":["Wrap value access in while (await reader.ReadAsync()) { ... } (or `if` for single-row expectations).","Use ExecuteScalar for single-value queries instead of a reader.","After NextResult(), always call Read() again before touching values.","Treat HasRows as a hint about data existing, never as permission to skip Read()."],"exampleFix":"// before\nusing var reader = command.ExecuteReader();\nvar name = reader.GetString(0); // Read() never called -> throws\n\n// after\nusing var reader = command.ExecuteReader();\nwhile (reader.Read())\n{\n    var name = reader.GetString(0);\n}","handlingStrategy":"validation","validationCode":"// only access values from a positioned reader\nif (reader.Read())\n{\n    var value = reader.GetString(0);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always gate value access behind Read()/ReadAsync() returning true.","Call Read() again after every NextResult().","Use ExecuteScalar for single-value queries instead of a reader.","Treat HasRows as a preview, not a positioning operation."],"tags":["dotnet","ado-net","reader-lifecycle","read-before-access"],"backgroundTag":"reader-before-read","analyzedSha":"6c7252267988c76e632af00a671e4b9788dfae13","analyzedAt":"2026-08-20T07:02:18.389Z","contentChangedAt":"2026-08-20T07:02:18.389Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}