dotnet/efcore · error · InvalidOperationException

The underlying reader doesn't have as many fields as…

Error message

The underlying reader doesn't have as many fields as expected. Expected: {expected}, actual: {actual}.

What it means

Thrown by BufferedDataReader when the underlying reader returns fewer fields than the entity expects, yet none of the expected column names are individually missing (so the prior per-name check passed). This indicates a structural field-count deficit rather than a name mismatch.

Solutions

  1. Ensure the SQL/procedure returns at least as many fields as the entity maps.
  2. Reduce the entity's mapped property count to match what the query actually returns, or split into a DTO.
  3. Update the database provider package so its reader reports fields consistently.
  4. Confirm FieldCount semantics for the underlying DbDataReader against the active provider.

Example fix

// before
var users = dbContext.Users.FromSqlInterpolated($"EXEC dbo.GetUsers").ToList();
// procedure returns 2 cols but User maps 3

// after: fix the procedure / SELECT to return all mapped columns
var users = dbContext.Users.FromSqlRaw("SELECT Id, Name, Email FROM Users").ToList();
Defensive patterns

Strategy: validation

Validate before calling

static void EnsureReaderFieldCount(DbDataReader reader, int expectedColumns)
{
    if (reader.FieldCount < expectedColumns)
        throw new InvalidOperationException($"Reader reports {reader.FieldCount} fields; expected at least {expectedColumns}.");
}

Prevention

When it happens

Trigger: InitializeFields finds FieldCount < _columns.Count but every expected column name resolves in the lookup; the throw uses TooFewReaderFields. Typically a provider/driver returning a narrower shape than the mapped entity in non-composed FromSql.

Common situations: Driver-level column suppression (e.g. provider returns computed columns lazily). Provider version change that alters field reporting. Mismatched schema between two reads of the same query. Computed/unused columns not emitted by stored procedures.

Related errors


AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11). Data as JSON: /api/errors/da0f4ed49aa5ca4d. Report an issue: GitHub.

Appendix: source

Thrown at src/EFCore.Relational/Query/Internal/BufferedDataReader.cs:1244

                return index;
            }
        }

        private void InitializeFields()
        {
            var fieldCount = FieldCount;
            if (FieldCount < _columns.Count)
            {
                // Non-composed FromSql
                var readerColumns = _fieldNameLookup.Value;

                var firstMissingColumn = _columns.Select(c => c?.Name).FirstOrDefault(c => c != null && !readerColumns.ContainsKey(c));
                if (firstMissingColumn != null)
                {
                    throw new InvalidOperationException(RelationalStrings.FromSqlMissingColumn(firstMissingColumn));
                }

                throw new InvalidOperationException(RelationalStrings.TooFewReaderFields(_columns.Count, FieldCount));
            }

            _columnTypeCases = Enumerable.Repeat(TypeCase.Empty, fieldCount).ToArray();
            _ordinalToIndexMap = Enumerable.Repeat(-1, fieldCount).ToArray();
            if (_columns.Count > 0
                && _columns.Any(e => e?.Name != null))
            {
                // Non-Composed FromSql
                var readerColumns = _fieldNameLookup.Value;

                _indexMap = new int[_columns.Count];
                var newColumnMap = new ReaderColumn?[fieldCount];
                for (var i = 0; i < _columns.Count; i++)
                {
                    var column = _columns[i];
                    if (column == null)
                    {
                        continue;

View on GitHub (pinned to 3a2006ef56)