tursodatabase/turso · error · TursoException

Unable to read native value bytes.

Error message

Unable to read native value bytes.

What it means

ReadBytes backs text and blob reads in the raw bindings: it first asks native code for the current value's byte count, and a negative count throws TursoException with this message. The native layer reporting no readable length for a value the type kind said was Text/Blob indicates the row is not currently valid — e.g. the statement was stepped past its data or is being disturbed concurrently.

Source

Thrown at bindings/dotnet/src/Turso.Raw/Public/TursoBindings.cs:406

        if (bytes.Length == 0)
            return bind(IntPtr.Zero);

        var handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
        try
        {
            return bind(handle.AddrOfPinnedObject());
        }
        finally
        {
            handle.Free();
        }
    }

    private static byte[] ReadBytes(TursoStatementHandle statement, UIntPtr index)
    {
        var length = TursoInterop.StatementRowValueBytesCount(statement, index);
        if (length < 0)
            throw new TursoException("Unable to read native value bytes.");
        if (length == 0)
            return [];

        var ptr = TursoInterop.StatementRowValueBytesPtr(statement, index);
        if (ptr == IntPtr.Zero)
            throw new TursoException("Unable to read native value bytes.");

        unsafe
        {
            var data = new ReadOnlySpan<byte>((void*)ptr, checked((int)length));
            return data.ToArray();
        }
    }

    private static UIntPtr ToNativeIndex(int index) => checked((UIntPtr)(ulong)index);

    private static UIntPtr ToNativeLength(int length) => checked((UIntPtr)(ulong)length);

View on GitHub (pinned to 6c72522679)

Solutions

  1. Only call GetValue after Read() returned true for that row, and read all columns before stepping again.
  2. Keep one statement on one thread/task; serialize access.
  3. Confirm the native library version matches the bindings package.
  4. If it persists with correct sequencing, capture the SQL, column kinds, and library versions and report it upstream.

Example fix

// before
var value = TursoBindings.GetValue(statement, 0); // no row stepped yet -> TursoException

// after
if (TursoBindings.Read(statement))
{
    var value = TursoBindings.GetValue(statement, 0);
}
Defensive patterns

Strategy: validation

Validate before calling

// step to a row before reading any value
if (TursoBindings.Read(statement))
{
    var value = TursoBindings.GetValue(statement, columnIndex);
}

Try / catch

try { v = TursoBindings.GetValue(stmt, i); }
catch (TursoException ex) when (ex.Message == "Unable to read native value bytes.") { /* row not current or version skew */ }

Prevention

When it happens

Trigger: Calling TursoBindings.GetValue(statement, i) (which routes Text/Blob kinds through ReadBytes) when the statement has no current row — before a successful Read(), after Read() returned false/Done, or after another thread re-stepped the statement; also possible with a native library that does not match the bindings.

Common situations: Missing `if (TursoBindings.Read(stmt))` guard before GetValue; sharing one statement across tasks; reading values after finalizing; version skew between the native turso library and the managed package.

Related errors


AI-assisted analysis of tursodatabase/turso@6c72522679 (2026-08-20). Data as JSON: /api/errors/08fdd487c9843957. Report an issue: GitHub.