{"record":{"id":"3b1251ec6060db5b","repo":"DapperLib/Dapper","slug":"the-rest-field-of-a-valuetuple-must-contain-a-nest","errorCode":null,"errorMessage":"The Rest field of a ValueTuple must contain a nested ValueTuple of arity 1 or greater.","messagePattern":"The Rest field of a ValueTuple must contain a nested ValueTuple of arity 1 or greater\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"Dapper/SqlMapper.cs","lineNumber":3413,"sourceCode":"\r\n                for (var i = 0; i < itemFieldCount; i++)\r\n                {\r\n                    languageTupleElementTypes.Add(constructorParameterTypes[i]);\r\n                }\r\n\r\n                if (restField is not null)\r\n                {\r\n                    constructorParameterTypes[constructorParameterTypes.Length - 1] = restField.FieldType;\r\n                }\r\n\r\n                constructors.Add(currentValueTupleType.GetConstructor(constructorParameterTypes)!);\r\n\r\n                if (restField is null) break;\r\n\r\n                currentValueTupleType = restField.FieldType;\r\n                if (!IsValueTuple(currentValueTupleType))\r\n                {\r\n                    throw new InvalidOperationException(\"The Rest field of a ValueTuple must contain a nested ValueTuple of arity 1 or greater.\");\r\n                }\r\n            }\r\n\r\n            var stringEnumLocal = (LocalBuilder?)null;\r\n\r\n            for (var i = 0; i < languageTupleElementTypes.Count; i++)\r\n            {\r\n                var targetType = languageTupleElementTypes[i];\r\n\r\n                if (i < length)\r\n                {\r\n                    LoadReaderValueOrBranchToDBNullLabel(\r\n                        il,\r\n                        startBound + i,\r\n                        ref stringEnumLocal,\r\n                        valueCopyLocal: null,\r\n                        reader.GetFieldType(startBound + i),\r\n                        targetType,\r","sourceCodeStart":3395,"sourceCodeEnd":3431,"githubUrl":"https://github.com/DapperLib/Dapper/blob/72a54c475f75e18cb93cba0809d00a5e6e49efd9/Dapper/SqlMapper.cs#L3395-L3431","documentation":"Thrown during ValueTuple deserializer IL generation when walking the Rest-chain of a ValueTuple result type and finding that the `Rest` field is not itself a ValueTuple. ValueTuples with more than 7 elements nest the overflow in a `Rest` field that must be another ValueTuple<...> of arity >= 1; if that invariant is broken (a malformed or hand-constructed tuple-like type), Dapper cannot continue the chain and throws InvalidOperationException.","triggerScenarios":"Mapping a query result onto a ValueTuple with 8+ elements whose Rest field is not a ValueTuple, or a user-defined struct that mimics ValueTuple layout (named like System.ValueTuple) but has a non-ValueTuple Rest. This is rare with normal C# tuples (the compiler always nests ValueTuples correctly) but can occur with reflection-built types or corrupted/signature-mismatched tuple types.","commonSituations":"Custom structs deliberately named to look like ValueTuple; very large tuple results (8+ columns mapped to a tuple) combined with a hand-rolled or IL-generated type; version skew where a tuple-shaped type changed its Rest field type.","solutions":["Map very wide results onto a named class/record instead of an 8+ element ValueTuple.","If you use a large tuple, ensure it is a genuine C# tuple so the compiler nests Rest correctly.","Avoid custom structs that imitate ValueTuple naming; use a real DTO.","Split the query into multiple smaller mappings."],"exampleFix":"// before (fragile, 8+ element tuple / custom Rest)\nvar rows = cnn.Query<(int a, string b, ..., int h, int i)>(sql);\n// after\npublic record WideRow(int A, string B, int C, int D, int E, int F, int G, int H, int I);\nvar rows = cnn.Query<WideRow>(sql);","handlingStrategy":"type-guard","validationCode":"// Avoid 8+ element tuples for results; map to a named DTO.\nvar rows = cnn.Query<WideRow>(sql);","typeGuard":"static bool HasValidRestChain(Type? t) { while (t is not null && t.FullName?.StartsWith(\"System.ValueTuple`\", StringComparison.Ordinal) == true) { var rest = t.GetField(\"Rest\"); if (rest is null) return true; if (!rest.FieldType.FullName?.StartsWith(\"System.ValueTuple`\", StringComparison.Ordinal) == true) return false; t = rest.FieldType; } return true; }","tryCatchPattern":null,"preventionTips":["Map wide results onto records/classes, not 8+ element tuples.","Use genuine C# tuples so the compiler nests Rest correctly.","Avoid hand-built structs that mimic ValueTuple naming."],"tags":["dapper","valuetuple","materialization","il-generation"],"backgroundTag":null,"analyzedSha":"72a54c475f75e18cb93cba0809d00a5e6e49efd9","analyzedAt":"2026-08-13T14:18:18.115Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}