DapperLib/Dapper · error · InvalidOperationException

The Rest field of a ValueTuple must contain a nested ValueTu

Error message

The Rest field of a ValueTuple must contain a nested ValueTuple of arity 1 or greater.

What it means

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.

Source

Thrown at Dapper/SqlMapper.cs:3413

                for (var i = 0; i < itemFieldCount; i++)
                {
                    languageTupleElementTypes.Add(constructorParameterTypes[i]);
                }

                if (restField is not null)
                {
                    constructorParameterTypes[constructorParameterTypes.Length - 1] = restField.FieldType;
                }

                constructors.Add(currentValueTupleType.GetConstructor(constructorParameterTypes)!);

                if (restField is null) break;

                currentValueTupleType = restField.FieldType;
                if (!IsValueTuple(currentValueTupleType))
                {
                    throw new InvalidOperationException("The Rest field of a ValueTuple must contain a nested ValueTuple of arity 1 or greater.");
                }
            }

            var stringEnumLocal = (LocalBuilder?)null;

            for (var i = 0; i < languageTupleElementTypes.Count; i++)
            {
                var targetType = languageTupleElementTypes[i];

                if (i < length)
                {
                    LoadReaderValueOrBranchToDBNullLabel(
                        il,
                        startBound + i,
                        ref stringEnumLocal,
                        valueCopyLocal: null,
                        reader.GetFieldType(startBound + i),
                        targetType,

View on GitHub (pinned to 72a54c475f)

Solutions

  1. Map very wide results onto a named class/record instead of an 8+ element ValueTuple.
  2. If you use a large tuple, ensure it is a genuine C# tuple so the compiler nests Rest correctly.
  3. Avoid custom structs that imitate ValueTuple naming; use a real DTO.
  4. Split the query into multiple smaller mappings.

Example fix

// before (fragile, 8+ element tuple / custom Rest)
var rows = cnn.Query<(int a, string b, ..., int h, int i)>(sql);
// after
public record WideRow(int A, string B, int C, int D, int E, int F, int G, int H, int I);
var rows = cnn.Query<WideRow>(sql);
Defensive patterns

Strategy: type-guard

Validate before calling

// Avoid 8+ element tuples for results; map to a named DTO.
var rows = cnn.Query<WideRow>(sql);

Type guard

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; }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of DapperLib/Dapper@72a54c475f (2026-08-13). Data as JSON: /api/errors/3b1251ec6060db5b. Report an issue: GitHub.