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
- Ensure the SQL/procedure returns at least as many fields as the entity maps.
- Reduce the entity's mapped property count to match what the query actually returns, or split into a DTO.
- Update the database provider package so its reader reports fields consistently.
- 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
- Make stored procedures/views return at least the mapped column count.
- Verify provider behavior after package upgrades.
- Prefer full-table SELECTs over narrow projections for entity materialization.
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
- The required column ' ' was not present in the results of a…
- An error occurred while reading a database value. The…
- An error occurred while reading a database value. The…
- An error occurred while reading a database value. See the…
- A FromSqlExpression has an invalid arguments expression type
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)