{"record":{"id":"91f6fce24717bc46","repo":"DapperLib/Dapper","slug":"you-must-provide-at-least-one-type-to-deserialize","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.Async.cs","lineNumber":979,"sourceCode":"        /// <param name=\"param\">The parameters to use for this query.</param>\r\n        /// <param name=\"transaction\">The transaction to use for this query.</param>\r\n        /// <param name=\"buffered\">Whether to buffer the results in memory.</param>\r\n        /// <param name=\"splitOn\">The field we should split and read the second object from (default: \"Id\").</param>\r\n        /// <param name=\"commandTimeout\">Number of seconds before command execution timeout.</param>\r\n        /// <param name=\"commandType\">Is it a stored proc or a batch?</param>\r\n        /// <returns>An enumerable of <typeparamref name=\"TReturn\"/>.</returns>\r\n        [System.Diagnostics.CodeAnalysis.SuppressMessage(\"ApiDesign\", \"RS0026:Do not add multiple public overloads with optional parameters\", Justification = \"Grandfathered\")]\r\n        public static Task<IEnumerable<TReturn>> QueryAsync<TReturn>(this IDbConnection cnn, string sql, Type[] types, Func<object[], TReturn> map, object? param = null, IDbTransaction? transaction = null, bool buffered = true, string splitOn = \"Id\", int? commandTimeout = null, CommandType? commandType = null)\r\n        {\r\n            var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, buffered ? CommandFlags.Buffered : CommandFlags.None, default);\r\n            return MultiMapAsync(cnn, command, types, map, splitOn);\r\n        }\r\n\r\n        private static async Task<IEnumerable<TReturn>> MultiMapAsync<TReturn>(this IDbConnection cnn, CommandDefinition command, Type[] types, Func<object[], TReturn> map, string splitOn)\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            var identity = new IdentityWithTypes(command.CommandText, command.CommandTypeDirect, cnn, types[0], param?.GetType(), types);\r\n            var info = GetCacheInfo(identity, param, command.AddToCache);\r\n            bool wasClosed = cnn.State == ConnectionState.Closed;\r\n            try\r\n            {\r\n                if (wasClosed) await cnn.TryOpenAsync(command.CancellationToken).ConfigureAwait(false);\r\n                using var cmd = command.TrySetupAsyncCommand(cnn, info.ParamReader);\r\n                using var reader = await ExecuteReaderWithFlagsFallbackAsync(cmd, wasClosed, CommandBehavior.SequentialAccess | CommandBehavior.SingleResult, command.CancellationToken).ConfigureAwait(false);\r\n                var results = MultiMapImpl(null, default, types, map, splitOn, reader, identity, true);\r\n                return command.Buffered ? results.ToList() : results;\r\n            }\r\n            finally\r\n            {\r\n                if (wasClosed) cnn.Close();\r\n            }\r","sourceCodeStart":961,"sourceCodeEnd":997,"githubUrl":"https://github.com/DapperLib/Dapper/blob/72a54c475f75e18cb93cba0809d00a5e6e49efd9/Dapper/SqlMapper.Async.cs#L961-L997","documentation":"MultiMapAsync (the multi-mapping async path, reached via QueryAsync<TReturn>(sql, Type[] types, map, ...)) throws ArgumentException(\"you must provide at least one type to deserialize\") when the types array has zero elements. Multi-mapping needs at least one source type to split the result set on; an empty array is unrecoverable. Checked after the CommandDefinition is built, before any connection work.","triggerScenarios":"Calling the multi-map QueryAsync overload with an empty Type[] types array (e.g. types built dynamically from a list that came back empty).","commonSituations":"Constructing the types array from config/metadata where the source list was empty; programmatically filtering types down to zero; a refactor that dropped the primary type from the array.","solutions":["Ensure the types array contains at least the primary type before calling the multi-map overload.","Validate the dynamically built types array length and throw a clearer upstream error if empty."],"exampleFix":"// before\nvar types = Array.Empty<Type>();\nvar rows = await cnn.QueryAsync<Foo>(sql, types, map);\n\n// after\nvar types = new[] { typeof(A), typeof(B) };\nvar rows = await cnn.QueryAsync<Foo>(sql, types, map);","handlingStrategy":"validation","validationCode":"if (types is null || types.Length < 1) throw new ArgumentException(\"At least one type is required for multi-mapping.\");\nvar rows = await cnn.QueryAsync<TReturn>(sql, types, map);","typeGuard":null,"tryCatchPattern":"try { await cnn.QueryAsync<TReturn>(sql, types, map); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"at least one type\"))\n{ /* populate the types array with the primary type and retry */ }","preventionTips":["Build the types array from a guaranteed-non-empty list (the primary type first).","Validate dynamically constructed arrays length before the multi-map call."],"tags":["argument","async","multi-mapping","query"],"backgroundTag":null,"analyzedSha":"72a54c475f75e18cb93cba0809d00a5e6e49efd9","analyzedAt":"2026-08-13T14:18:18.115Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}