{"record":{"id":"347bfdce39d2e7e7","repo":"dotnet/efcore","slug":"empty-collections-are-not-supported-as-inline-quer","errorCode":null,"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/3a2006ef569de08368d59db5e1468aa8f407e4f8/src/EFCore.Relational/Query/QuerySqlGenerator.cs#L1602-L1638","documentation":"GenerateValues refuses to render a VALUES inline query root that contains zero rows. EF translates certain in-memory collections used as query roots into a VALUES construct; an empty collection has no columns/types to project, so SQL generation is impossible. The check is hit at SQL-generation time, meaning the query already passed translation with an empty row set.","triggerScenarios":"Using an empty in-memory collection as a query root in a composed query that EF translates server-side, e.g. from e in db.Entities from id in emptyArray.AsQueryable() select e, or Contains over a parameterized empty list that EF chose to inline as VALUES instead of a parameter. Also seen with open-ended composition where a sub-source resolves empty at execution.","commonSituations":"Dynamic filters where a list can be empty (e.g. var ids = FilterIds(); ... where ids.Contains(e.Id)); joining against an in-memory list that happens to be empty for a given request; unit/integration tests passing empty collections.","solutions":["Short-circuit before the query when the collection is empty (return an empty result or skip the predicate/join).","For Contains filters, build the predicate conditionally so EF never inlines an empty VALUES: if (ids.Count > 0) query = query.Where(e => ids.Contains(e.Id));","Avoid using empty in-memory sequences as query roots; materialize the server side first, then join in memory."],"exampleFix":"// before\nvar q = from e in db.Entities\n        from id in ids.AsQueryable()   // ids may be empty -> 585\n        select new { e, id };\n// after\nif (ids.Count == 0) return Array.Empty<Result>();\nvar q = from e in db.Entities\n        from id in ids.AsQueryable()\n        select new { e, id };","handlingStrategy":"validation","validationCode":"// Never hand EF an empty inline collection as a query root / Contains source.\nif (ids is null || ids.Count == 0)\n    return Array.Empty<Result>();\n\nvar q = db.Entities.Where(e => ids.Contains(e.Id));\n\n// For an in-memory root join:\nif (memoryList.Count == 0) return Enumerable.Empty<Result>();","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Guard dynamic filter lists for emptiness before composing Contains/join.","Build Contains predicates conditionally so EF never sees an empty VALUES root.","Materialize server data first, then join in memory when the in-memory side may be empty."],"tags":["efcore","values","query-root","empty-collection","query-translation"],"backgroundTag":null,"analyzedSha":"3a2006ef569de08368d59db5e1468aa8f407e4f8","analyzedAt":"2026-08-11T23:42:04.146Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}