tursodatabase/turso · warning · InvalidOperationException

Parameter index {index} is too large.

Error message

Parameter index {index} is too large.

What it means

BindNamedParameter resolves a parameter name to its native 1-based position via StatementNamedPosition. Positions below 1 mean the name does not exist and the method silently returns 0 without binding; a position above int.MaxValue instead throws InvalidOperationException. SQLite's variable limit sits orders of magnitude below int.MaxValue, so in practice this throw signals a corrupted or ABI-mismatched native return rather than a realistic parameter count.

Source

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

    public static void BindParameter(TursoStatementHandle statement, int index, TursoValue parameter)
    {
        statement.ThrowIfInvalid();
        ArgumentOutOfRangeException.ThrowIfNegativeOrZero(index);

        BindParameterAt(statement, index, parameter);
    }

    public static int BindNamedParameter(TursoStatementHandle statement, string name, TursoValue parameter)
    {
        statement.ThrowIfInvalid();
        ArgumentNullException.ThrowIfNull(name);

        var index = TursoInterop.StatementNamedPosition(statement, name);
        if (index < 1)
            return 0;
        if (index > int.MaxValue)
            throw new InvalidOperationException($"Parameter index {index} is too large.");

        BindParameterAt(statement, (int)index, parameter);
        return (int)index;
    }

    public static bool Read(TursoStatementHandle statement)
        => Read(statement, runExternalIo: null);

    public static bool Read(TursoStatementHandle statement, Action? runExternalIo)
    {
        statement.ThrowIfInvalid();

        while (true)
        {
            var status = TursoInterop.StatementStep(statement, out var errorPtr);
            if (status == TursoStatusCode.Row)
                return true;
            if (status == TursoStatusCode.Done)

View on GitHub (pinned to 6c72522679)

Solutions

  1. Verify the named parameter exists before relying on binding: check the return value of BindNamedParameter (0 means the name was not found) and enumerate names with GetParameterName.
  2. Match native library and managed binding versions (same release set) so the position contract holds.
  3. Use positional BindParameter with indexes from GetParameterCount when names are not required.
  4. If it throws with a modest statement, capture SQL and parameter names and report it as a bindings/native mismatch bug.
Defensive patterns

Strategy: validation

Validate before calling

// verify the name exists before relying on the binding
int pos = TursoInterop.StatementNamedPosition(statement, name); // or use the BindNamedParameter return value
if (TursoBindings.BindNamedParameter(statement, name, value) == 0)
    throw new InvalidOperationException($"Parameter {name} not found on statement");

Try / catch

try { TursoBindings.BindNamedParameter(stmt, name, value); }
catch (InvalidOperationException ex) when (ex.Message.Contains("too large")) { /* native/managed version mismatch: realign packages */ }

Prevention

When it happens

Trigger: A native turso library whose StatementNamedPosition returns a garbage/huge value — typically after mixing bindings and native library versions; hypothetically a generated statement with more than 2^31-1 parameters, which the engine would reject anyway.

Common situations: Upgrading the managed NuGet package without shipping the matching native library (or vice versa); custom interop shims changing the position return contract. The far more common gotcha nearby is the silent return-0 path: a typo'd parameter name simply never binds.

Related errors


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