{"record":{"id":"0e9cd18696383e7a","repo":"dotnet/efcore","slug":"emptycollectionnotsupportedasinlinequeryroot","errorCode":"EmptyCollectionNotSupportedAsInlineQueryRoot","errorMessage":"Empty collections are not supported as inline query roots.","messagePattern":"Empty collections are not supported as inline query roots\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Query/QuerySqlGenerator.cs","lineNumber":1620,"sourceCode":"\n        _relationalCommandBuilder\n            .Append(\")\")\n            .Append(AliasSeparator)\n            .Append(_sqlGenerationHelper.DelimitIdentifier(valuesExpression.Alias));\n\n        return valuesExpression;\n    }\n\n    /// <summary>\n    ///     Generates SQL for a VALUES expression.\n    /// </summary>\n    /// <param name=\"valuesExpression\">The <see cref=\"ValuesExpression\" /> for which to generate SQL.</param>\n    protected virtual void GenerateValues(ValuesExpression valuesExpression)\n    {\n        var rowValues = valuesExpression switch\n        {\n            { RowValues.Count: 0 }\n                => throw new InvalidOperationException(RelationalStrings.EmptyCollectionNotSupportedAsInlineQueryRoot),\n\n            { ValuesParameter: not null }\n                => throw new UnreachableException(\n                    \"ValuesExpression.ValuesParameter has to be expanded to constants before SQL generation (i.e. in SqlNullabilityProcessor)\"),\n\n            { RowValues: not null } => valuesExpression.RowValues,\n\n            _ => throw new UnreachableException()\n        };\n\n        // Some databases support providing the names of columns projected out of VALUES, e.g.\n        // SQL Server/PG: (VALUES (1, 3), (2, 4)) AS x(a, b). Others unfortunately don't; so by default, we extract out the first row,\n        // and generate a SELECT for it with the names, and a UNION ALL over the rest of the values.\n        _relationalCommandBuilder.Append(\"SELECT \");\n\n        Check.DebugAssert(rowValues.Count > 0);\n        var firstRowValues = rowValues[0].Values;\n        for (var i = 0; i < firstRowValues.Count; i++)","sourceCodeStart":1602,"sourceCodeEnd":1638,"githubUrl":"https://github.com/dotnet/efcore/blob/dbf9771522148d61a2467854921bd5dc6f6e6916/src/EFCore.Relational/Query/QuerySqlGenerator.cs#L1602-L1638","documentation":"Thrown by GenerateValues when a ValuesExpression (the inline VALUES construct EF builds for parameterized collections) has zero rows. EF inlines small client collections as a VALUES query root (e.g. for Contains), but an empty VALUES clause cannot be emitted as a standalone query root, so it is rejected.","triggerScenarios":"A LINQ query that forces a collection into an inline query root while that collection is empty - typically db.Set<T>().Where(e => someEmptyList.Contains(e.Id)) where the provider decides to inline the empty list rather than expand it to a false predicate. Also any manual construction that yields a ValuesExpression with RowValues.Count == 0.","commonSituations":"Dynamic filters where an optional list happens to be empty at runtime; EF version differences in how empty Contains collections are lowered; provider-specific behavior that routes to inline VALUES rather than the standard 'WHERE 1=0' short-circuit.","solutions":["Guard the query: skip the Contains predicate (or short-circuit to an empty result) when the collection is empty.","Materialize the collection to a non-empty placeholder or pass the list as a parameter that EF handles via parameterized IN expansion.","Upgrade EF Core; the inline-VALUES path is progressively better at short-circuiting empty inputs across releases.","If authoring a provider, ensure empty collections are translated to a universally-false predicate rather than an inline VALUES root."],"exampleFix":"// before\nvar ids = new List<int>();\nvar posts = db.Posts.Where(p => ids.Contains(p.Id)).ToList(); // may hit inline empty VALUES\n// after\nvar ids = new List<int>();\nvar posts = ids.Count == 0\n    ? new List<Post>()\n    : db.Posts.Where(p => ids.Contains(p.Id)).ToList();","handlingStrategy":"validation","validationCode":"IReadOnlyList<int> ids = GetIds();\nif (ids.Count == 0) return Array.Empty<Post>();\nreturn db.Posts.Where(p => ids.Contains(p.Id)).ToList();","typeGuard":null,"tryCatchPattern":"try { return db.Posts.Where(p => ids.Contains(p.Id)).ToList(); }\ncatch (InvalidOperationException ex) when (ids.Count == 0 && ex.Message.Contains(\"Empty collections\"))\n{ return Array.Empty<Post>(); }","preventionTips":["Short-circuit queries when the input collection is empty.","Prefer Any/All over Contains when the collection may be empty.","Upgrade EF Core to benefit from improved empty-collection short-circuiting.","If authoring a provider, lower empty Contains to 'WHERE 1=0' rather than inline VALUES."],"tags":["contains","inline-values","query-translation","collections"],"analyzedSha":"dbf9771522148d61a2467854921bd5dc6f6e6916","analyzedAt":"2026-08-06T20:46:03.226Z","schemaVersion":2},"datasetVersion":"2026-08-07T02:17:10.218Z"}