dotnet/efcore · error · InvalidOperationException
Custom translation cannot be set on the DbFunction '{functio
Error message
Custom translation cannot be set on the DbFunction '{function}' since it is not a scalar function. What it means
Thrown by DbFunction.SetTranslation when a custom translation delegate is set on a function that is not a scalar, non-aggregate function (i.e. IsScalar is false or IsAggregate is true). Custom translation is only supported for scalar functions whose arguments map to a single SqlExpression result.
Source
Thrown at src/EFCore.Relational/Metadata/Internal/DbFunction.cs:611
set => SetTranslation(value, ConfigurationSource.Explicit);
}
/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public virtual Func<IReadOnlyList<SqlExpression>, SqlExpression>? SetTranslation(
Func<IReadOnlyList<SqlExpression>, SqlExpression>? translation,
ConfigurationSource configurationSource)
{
EnsureMutable();
if (translation != null
&& (!IsScalar || IsAggregate))
{
throw new InvalidOperationException(RelationalStrings.DbFunctionNonScalarCustomTranslation(MethodInfo?.DisplayName()));
}
_translation = translation;
_translationConfigurationSource = translation == null
? null
: configurationSource.Max(_translationConfigurationSource);
return translation;
}
/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public virtual ConfigurationSource? GetTranslationConfigurationSource()View on GitHub (pinned to dbf9771522)
Solutions
- Remove the HasTranslation call from TVF and aggregate functions; custom translation applies only to scalar functions.
- Guard: only set translation when the function is scalar and non-aggregate.
- For TVFs, map them as queryable functions returning an entity type instead of providing a translation.
- If the function is meant to be scalar, ensure its return type is a scalar so IsScalar is true and IsAggregate stays false.
Example fix
// before
public IQueryable<Order> RecentOrders() => /* tvf */;
modelBuilder.HasDbFunction(typeof(Ctx).GetMethod("RecentOrders"))
.HasTranslation(args => /* SqlExpression */ null!); // throws
// after
public IQueryable<Order> RecentOrders() => /* tvf */;
modelBuilder.HasDbFunction(typeof(Ctx).GetMethod("RecentOrders"));
// HasTranslation only for scalar fns:
public decimal TaxFor(decimal amount) => 0m;
modelBuilder.HasDbFunction(typeof(Ctx).GetMethod("TaxFor"))
.HasTranslation(args => new SqlBinaryExpression(...)); Defensive patterns
Strategy: validation
Validate before calling
// Only set translation for scalar, non-aggregate functions
if (fn.IsScalar && !fn.IsAggregate)
{
fn.Builder.HasTranslation(translate, fromDataAnnotation: true);
} Type guard
static bool SupportsCustomTranslation(IDbFunction fn) => fn is { IsScalar: true, IsAggregate: false }; Prevention
- Reserve HasTranslation for scalar functions only.
- Separate TVF mapping (entity return) from scalar translation in config helpers.
- Guard configuration loops with an IsScalar check before applying translation.
When it happens
Trigger: Calling HasTranslation(...) on a table-valued function (IQueryable<T> return) or on a function marked IsAggregate. Surfaced through InternalDbFunctionBuilder.HasTranslation -> Metadata.SetTranslation.
Common situations: Applying a shared DbFunction configuration routine that calls HasTranslation to all functions, including TVFs and aggregates. Or trying to translate a TVF's row set the way you would a scalar.
Related errors
- The DbFunction '{function}' has an invalid return type '{typ
- 'IsNullable' cannot be set on DbFunction '{functionName}' si
- 'PropagatesNullability' cannot be set on parameter '{paramet
- The DbFunction '{function}' is generic. Mapping generic meth
- The DbFunction '{function}' defined on type '{type}' must be
AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06).
Data as JSON: /api/errors/512631e12a7cb1e4.
Report an issue: GitHub.