{"record":{"id":"ff78025162d2f7ec","repo":"tursodatabase/turso","slug":"parameter-must-be-of-type-tursoparameter","errorCode":null,"errorMessage":"Parameter must be of type TursoParameter","messagePattern":"Parameter must be of type TursoParameter","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"bindings/dotnet/src/Turso.Data/TursoCommand.cs","lineNumber":180,"sourceCode":"        if (string.IsNullOrWhiteSpace(CommandText))\n            throw new InvalidOperationException(\"CommandText must be set before preparing a command.\");\n        ValidateTransaction();\n        if (_connection.IsRemote)\n            return;\n\n        TursoStatementHandle? preparedStatement = null;\n        try\n        {\n            var sql = RewriteFacadePragmas(CommandText, _connection);\n            preparedStatement = TursoBindings.PrepareStatement(_connection.Turso, sql);\n            var parameterCount = TursoBindings.GetParameterCount(preparedStatement);\n            var boundParameters = new bool[parameterCount + 1];\n\n            for (var i = 0; i < _parameterCollection.Count; i++)\n            {\n                var parameter = _parameterCollection[i] as TursoParameter;\n                if (parameter == null)\n                    throw new ArgumentException(\"Parameter must be of type TursoParameter\");\n\n                if (!string.IsNullOrEmpty(parameter.ParameterName))\n                {\n                    var parameterIndex = TursoBindings.BindNamedParameter(preparedStatement, parameter.ParameterName, parameter.ToValue());\n                    if (parameterIndex == 0)\n                        throw new InvalidOperationException($\"Parameter {parameter.ParameterName} was not found in the SQL statement.\");\n\n                    boundParameters[parameterIndex] = true;\n                }\n                else\n                {\n                    var parameterIndex = i + 1;\n                    if (parameterIndex > parameterCount)\n                        throw new InvalidOperationException($\"Parameter at position {parameterIndex} was not found in the SQL statement.\");\n\n                    TursoBindings.BindParameter(preparedStatement, parameterIndex, parameter.ToValue());\n                    boundParameters[parameterIndex] = true;\n                }","sourceCodeStart":162,"sourceCodeEnd":198,"githubUrl":"https://github.com/tursodatabase/turso/blob/c1e59287258d99b309e362a63f48822256e2f65f/bindings/dotnet/src/Turso.Data/TursoCommand.cs#L162-L198","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Create parameters with cmd.CreateParameter() or cmd.Parameters.AddWithValue(name, value) so every entry is a TursoParameter.","Do not subclass or swap out the parameter collection that TursoCommand uses.","If you wrap parameters generically, unwrap to a TursoParameter (or its raw value) before inserting into Parameters."],"exampleFix":"// before\ncustomWrapperCollection.Add(new SqlParameter(\"@id\", 42));\ncmd.Prepare(); // indexer returns SqlParameter -> throws ArgumentException\n\n// after\ncmd.Parameters.AddWithValue(\"@id\", 42);\ncmd.Prepare();","handlingStrategy":"type-guard","validationCode":"foreach (DbParameter p in cmd.Parameters)\n{\n    if (p is not TursoParameter)\n        throw new InvalidOperationException($\"{p.GetType().Name} cannot be bound by TursoCommand.\");\n}","typeGuard":"static bool AllParametersAreTurso(DbParameterCollection ps) => ps.Cast<DbParameter>().All(p => p is TursoParameter);","tryCatchPattern":"try\n{\n    cmd.Prepare();\n}\ncatch (ArgumentException ex) when (ex.Message.Contains(\"TursoParameter\"))\n{\n    // Rebuild the collection with cmd.CreateParameter()/AddWithValue and retry.\n}","preventionTips":["Add parameters only via cmd.Parameters.AddWithValue or cmd.CreateParameter().","Do not subclass or replace the parameter collection used by TursoCommand.","Unwrap foreign DbParameter objects to plain values before inserting."],"tags":["dotnet","ado-net","tursodb","parameters","type-mismatch"],"backgroundTag":"ado-net-provider-type-mismatch","analyzedSha":"c1e59287258d99b309e362a63f48822256e2f65f","analyzedAt":"2026-08-20T07:02:18.389Z","contentChangedAt":"2026-08-20T07:02:18.389Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}