{"record":{"id":"34b194caf48402fa","repo":"DapperLib/Dapper","slug":"you-must-provide-at-least-one-type-to-deserialize-34b194","errorCode":null,"errorMessage":"you must provide at least one type to deserialize","messagePattern":"you must provide at least one type to deserialize","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"Dapper/SqlMapper.cs","lineNumber":1654,"sourceCode":"                finally\r\n                {\r\n                    ownedCommand?.Parameters.Clear();\r\n                    ownedCommand?.Dispose();\r\n                    if (wasClosed) cnn!.Close();\r\n                }\r\n            }\r\n        }\r\n\r\n        private static CommandBehavior GetBehavior(bool close, CommandBehavior @default)\r\n        {\r\n            return (close ? (@default | CommandBehavior.CloseConnection) : @default) & Settings.AllowedCommandBehaviors;\r\n        }\r\n\r\n        private static IEnumerable<TReturn> MultiMapImpl<TReturn>(this IDbConnection? cnn, CommandDefinition command, Type[] types, Func<object[], TReturn> map, string splitOn, DbDataReader? reader, Identity? identity, bool finalize)\r\n        {\r\n            if (types.Length < 1)\r\n            {\r\n                throw new ArgumentException(\"you must provide at least one type to deserialize\");\r\n            }\r\n\r\n            object? param = command.Parameters;\r\n            identity ??= new IdentityWithTypes(command.CommandText, command.CommandTypeDirect, cnn!, types[0], param?.GetType(), types);\r\n            CacheInfo cinfo = GetCacheInfo(identity, param, command.AddToCache);\r\n\r\n            IDbCommand? ownedCommand = null;\r\n            DbDataReader? ownedReader = null;\r\n\r\n            bool wasClosed = cnn?.State == ConnectionState.Closed;\r\n            try\r\n            {\r\n                if (reader is null)\r\n                {\r\n                    ownedCommand = command.SetupCommand(cnn!, cinfo.ParamReader);\r\n                    if (wasClosed) cnn!.Open();\r\n                    ownedReader = ExecuteReaderWithFlagsFallback(ownedCommand, wasClosed, CommandBehavior.SequentialAccess | CommandBehavior.SingleResult);\r\n                    reader = ownedReader;\r","sourceCodeStart":1636,"sourceCodeEnd":1672,"githubUrl":"https://github.com/DapperLib/Dapper/blob/72a54c475f75e18cb93cba0809d00a5e6e49efd9/Dapper/SqlMapper.cs#L1636-L1672","documentation":"Thrown by MultiMapImpl when the `types` array passed to a multi-mapping query has zero elements. Dapper needs at least one concrete type so it can build a deserializer for the first result set; an empty array gives it nothing to map onto. This guards the non-generic `Query<TReturn>(cnn, sql, Type[] types, ...)` overload (SqlMapper.cs:1569), which is the only public entry point that lets the caller supply the type list directly.","triggerScenarios":"Calling `connection.Query<TReturn>(sql, types: Array.Empty<Type>(), map: arr => ...)` or passing any zero-length `Type[]` as the third argument to that overload. The generic `Query<TFirst,TSecond,...>` overloads never hit this because they always construct a populated type array internally.","commonSituations":"Dynamically building the `types` array from reflection or user input and forgetting the case where the source list is empty; refactoring away the last mapped type; copy-pasting a multi-map call and deleting the type arguments.","solutions":["Pass at least one Type in the array, e.g. `new[] { typeof(Customer) }`.","If you do not need multi-mapping, switch to the plain `Query<T>(sql)` overload instead of the `Type[]` overload.","Guard the caller: if `types.Length == 0`, skip the query or throw a clearer domain-level exception.","Prefer the strongly-typed generic `Query<TFirst,TSecond,TReturn>(...)` overload so the compiler enforces the type count."],"exampleFix":"// before\nvar rows = cnn.Query<Result>(sql, new Type[0], objs => (Result)objs[0]);\n// after\nvar rows = cnn.Query<Result>(sql, new[] { typeof(Result) }, objs => (Result)objs[0]);","handlingStrategy":"validation","validationCode":"if (types is null || types.Length < 1) throw new ArgumentException(\"Multi-map requires at least one type.\", nameof(types));\nvar rows = cnn.Query<TReturn>(sql, types, map, param);","typeGuard":"static bool HasMapTypes(Type[] types) => types is not null && types.Length > 0;","tryCatchPattern":null,"preventionTips":["Prefer the generic Query<TFirst,TSecond,TReturn> overload so the compiler fixes the type count.","When building Type[] dynamically, assert Length > 0 before the call.","Unit-test the dynamic type-building path against an empty source list."],"tags":["dapper","multimap","argument","validation"],"backgroundTag":null,"analyzedSha":"72a54c475f75e18cb93cba0809d00a5e6e49efd9","analyzedAt":"2026-08-13T14:18:18.115Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}