{"record":{"id":"f197af4a035f6e5f","repo":"dotnet/efcore","slug":"the-dbfunction-function-has-an-invalid-return-f197af","errorCode":null,"errorMessage":"The DbFunction '{function}' has an invalid return type '{type}'. Non-scalar functions must return 'IQueryable' of a valid entity type.","messagePattern":"The DbFunction '(.+?)' has an invalid return type '(.+?)'\\. Non-scalar functions must return 'IQueryable' of a valid entity type\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Metadata/Conventions/TableValuedDbFunctionConvention.cs","lineNumber":65,"sourceCode":"    }\n\n    /// <summary>\n    ///     Called when an <see cref=\"IConventionDbFunction\" /> is added to the model.\n    /// </summary>\n    /// <param name=\"dbFunctionBuilder\">The builder for the <see cref=\"IConventionDbFunction\" />.</param>\n    private static void ProcessDbFunctionAdded(\n        IConventionDbFunctionBuilder dbFunctionBuilder)\n    {\n        var function = dbFunctionBuilder.Metadata;\n        if (function.IsScalar)\n        {\n            return;\n        }\n\n        var elementType = function.ReturnType.TryGetElementType(typeof(IQueryable<>))!;\n        if (!elementType.IsValidEntityType())\n        {\n            throw new InvalidOperationException(\n                RelationalStrings.DbFunctionInvalidIQueryableReturnType(\n                    function.ModelName, function.ReturnType.ShortDisplayName()));\n        }\n\n        var model = function.Model;\n        var entityType = model.FindEntityType(elementType);\n        if (entityType?.IsOwned() == true\n            || model.IsOwned(elementType)\n            || (entityType == null && model.FindEntityTypes(elementType).Any()))\n        {\n            return;\n        }\n\n        dbFunctionBuilder.ModelBuilder.Entity(elementType);\n    }\n}\n","sourceCodeStart":47,"sourceCodeEnd":82,"githubUrl":"https://github.com/dotnet/efcore/blob/3a2006ef569de08368d59db5e1468aa8f407e4f8/src/EFCore.Relational/Metadata/Conventions/TableValuedDbFunctionConvention.cs#L47-L82","documentation":"When a DbFunction is registered as a non-scalar (table-valued) function, EF Core requires its return type to be IQueryable<T> where T is a valid entity type mapped in the model. This throw from TableValuedDbFunctionConvention.ProcessDbFunctionAdded fires when the element type is not a recognized entity, so EF cannot map the TVF result rows.","triggerScenarios":"Registering a method whose return type is IQueryable<T> where T is a non-entity class, a primitive, or an owned type that is not declared as an entity; calling HasDbFunction on a method returning IQueryable<object> or IQueryable<dynamic>.","commonSituations":"Adding a TVF mapping before declaring the result type as an entity; using a DTO as the TVF return type instead of a configured entity; switching a scalar function to a TVF and forgetting to register the return type.","solutions":["Make the type used as the IQueryable<T> argument a real entity: call modelBuilder.Entity<T>() or otherwise include T in the model before registering the DbFunction.","Ensure T is not an owned type unless it is also a valid principal entity (note the convention allows owned types only when explicitly registered — verify your scenario).","If the function is actually scalar, change the return type to a scalar (non-IQueryable) so EF treats it as a scalar function instead."],"exampleFix":"// before\npublic IQueryable<OrderSummary> GetOrderSummaries() => FromSqlInterpolated(...);\nmodelBuilder.HasDbFunction(typeof(MyContext).GetMethod(nameof(GetOrderSummaries)));\n// OrderSummary is not registered as an entity\n\n// after\nmodelBuilder.Entity<OrderSummary>(b => { /* key + mappings */ });\nmodelBuilder.HasDbFunction(typeof(MyContext).GetMethod(nameof(GetOrderSummaries)));","handlingStrategy":"validation","validationCode":"// Validate the element type is a registered entity before registering the TVF\nvar elementType = typeof(OrderSummary);\nif (!modelBuilder.Model.FindEntityType(elementType).IsKeyless\n    && modelBuilder.Model.FindEntityType(elementType) is null)\n{\n    throw new InvalidOperationException($\"{elementType.Name} must be registered as an entity before mapping the TVF.\");\n}\nmodelBuilder.HasDbFunction(typeof(MyContext).GetMethod(nameof(MyContext.GetOrderSummaries)));","typeGuard":"static bool IsMappableEntityTvfResult(Type t, IModel model)\n    => model.FindEntityType(t) is { } et && !et.IsKeyless;","tryCatchPattern":null,"preventionTips":["Register the result entity type before calling HasDbFunction for any TVF.","Avoid using DTOs as TVF return types; map a real entity with a key.","Add a test that asserts every TVF's IQueryable<T> element type resolves to a mapped entity."],"tags":["relational","dbfunctions","table-valued-functions","model-building"],"backgroundTag":null,"analyzedSha":"3a2006ef569de08368d59db5e1468aa8f407e4f8","analyzedAt":"2026-08-11T23:42:04.146Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}