tursodatabase/turso · error · ArgumentException

Parameter must be of type TursoParameter

Error message

Parameter must be of type TursoParameter

What it means

Inside Prepare(), every parameter read from the Parameters collection is cast to TursoParameter before its value can be marshalled to the native engine via ToValue() (TursoCommand.cs:170-174). A failed cast throws ArgumentException. Note that the stock TursoParameterCollection wraps foreign objects into TursoParameter on Add/Insert, so in practice this is a defensive invariant most reachable through a derived parameter collection or overridden parameter accessors.

Source

Thrown at bindings/dotnet/src/Turso.Data/TursoCommand.cs:180

        if (string.IsNullOrWhiteSpace(CommandText))
            throw new InvalidOperationException("CommandText must be set before preparing a command.");
        ValidateTransaction();
        if (_connection.IsRemote)
            return;

        TursoStatementHandle? preparedStatement = null;
        try
        {
            var sql = RewriteFacadePragmas(CommandText, _connection);
            preparedStatement = TursoBindings.PrepareStatement(_connection.Turso, sql);
            var parameterCount = TursoBindings.GetParameterCount(preparedStatement);
            var boundParameters = new bool[parameterCount + 1];

            for (var i = 0; i < _parameterCollection.Count; i++)
            {
                var parameter = _parameterCollection[i] as TursoParameter;
                if (parameter == null)
                    throw new ArgumentException("Parameter must be of type TursoParameter");

                if (!string.IsNullOrEmpty(parameter.ParameterName))
                {
                    var parameterIndex = TursoBindings.BindNamedParameter(preparedStatement, parameter.ParameterName, parameter.ToValue());
                    if (parameterIndex == 0)
                        throw new InvalidOperationException($"Parameter {parameter.ParameterName} was not found in the SQL statement.");

                    boundParameters[parameterIndex] = true;
                }
                else
                {
                    var parameterIndex = i + 1;
                    if (parameterIndex > parameterCount)
                        throw new InvalidOperationException($"Parameter at position {parameterIndex} was not found in the SQL statement.");

                    TursoBindings.BindParameter(preparedStatement, parameterIndex, parameter.ToValue());
                    boundParameters[parameterIndex] = true;
                }

View on GitHub (pinned to c1e5928725)

Solutions

  1. Create parameters with cmd.CreateParameter() or cmd.Parameters.AddWithValue(name, value) so every entry is a TursoParameter.
  2. Do not subclass or swap out the parameter collection that TursoCommand uses.
  3. If you wrap parameters generically, unwrap to a TursoParameter (or its raw value) before inserting into Parameters.

Example fix

// before
customWrapperCollection.Add(new SqlParameter("@id", 42));
cmd.Prepare(); // indexer returns SqlParameter -> throws ArgumentException

// after
cmd.Parameters.AddWithValue("@id", 42);
cmd.Prepare();
Defensive patterns

Strategy: type-guard

Validate before calling

foreach (DbParameter p in cmd.Parameters)
{
    if (p is not TursoParameter)
        throw new InvalidOperationException($"{p.GetType().Name} cannot be bound by TursoCommand.");
}

Type guard

static bool AllParametersAreTurso(DbParameterCollection ps) => ps.Cast<DbParameter>().All(p => p is TursoParameter);

Try / catch

try
{
    cmd.Prepare();
}
catch (ArgumentException ex) when (ex.Message.Contains("TursoParameter"))
{
    // Rebuild the collection with cmd.CreateParameter()/AddWithValue and retry.
}

Prevention

When it happens

Trigger: A custom TursoParameterCollection/DbParameterCollection subclass that stores and returns foreign DbParameter instances (e.g. a wrapping SqlParameter), which Prepare() then reads through the indexer; not producible by the built-in collection's public Add paths.

Common situations: Hand-rolled wrapper collections layered over the ADO.NET types; interop code that shuttles base DbParameter objects between providers; extremely rare with the shipped API surface.

Related errors


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