dotnet/efcore · error · InvalidOperationException

The function ' ' has a custom translation. A compiled model…

Error message

The function '{function}' has a custom translation. A compiled model cannot be generated because custom function translations are not supported.

What it means

Thrown by RelationalCSharpRuntimeAnnotationCodeGenerator when generating a compiled model if a DbFunction has a custom Translation delegate (function.Translation != null). Compiled models serialize the model into generated C#; arbitrary translation delegates (method references to user code) cannot be serialized into the compiled model, so the build is blocked.

Solutions

  1. Remove the custom HasTranslation delegate and rely on a database-side function / default translation when using compiled models.
  2. Keep the compiled model but exclude/opt out for that context and run without compilation.
  3. Move the custom translation into a provider extension or a SQL UDF instead of a runtime delegate.

Example fix

// before
modelBuilder.HasDbFunction(typeof(MyFunctions).GetMethod(nameof(MyFunctions.MyCustom))!)
    .HasTranslation(args => new SqlFunctionExpression(...)); // blocks compiled model
// dotnet ef dbcontext optimize -> throws

// after: map to a database function instead
modelBuilder.HasDbFunction(typeof(MyFunctions).GetMethod(nameof(MyFunctions.MyCustom))!)
    .HasName("my_custom");
Defensive patterns

Strategy: validation

Validate before calling

// Before generating a compiled model, ensure no DbFunction has a custom translation
foreach (var fn in modelBuilder.Model.GetDbFunctions())
{
    if (fn.Translation != null)
        throw new InvalidOperationException($"DbFunction {fn.Name} has a custom translation; remove HasTranslation before compiling the model.");
}
// dotnet ef dbcontext optimize

Prevention

When it happens

Trigger: Running 'dotnet ef dbcontext optimize' / compiled-model generation while a DbFunction is registered with HasTranslation(...) providing a custom SQL translation delegate.

Common situations: A model uses modelBuilder.HasDbFunction(...).HasTranslation(t => ...) to translate a CLR method to custom SQL, and the project then opts into compiled models for startup performance.

Related errors


AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11). Data as JSON: /api/errors/a4fbb4464ef8a2f8. Report an issue: GitHub.

Appendix: source

Thrown at src/EFCore.Relational/Design/Internal/RelationalCSharpRuntimeAnnotationCodeGenerator.cs:1832

                    .Append(tableVariable).Append($".AddRowInternalForeignKey({structuralTypeVariable}, ")
                    .AppendLine("RelationalModel.GetForeignKey(this,").IncrementIndent()
                    .AppendLine($"{code.Literal(internalForeignKey.DeclaringEntityType.Name)},")
                    .AppendLine($"{code.Literal(internalForeignKey.Properties.Select(p => p.Name).ToArray())},")
                    .AppendLine($"{code.Literal(internalForeignKey.PrincipalEntityType.Name)},")
                    .AppendLine($"{code.Literal(internalForeignKey.PrincipalKey.Properties.Select(p => p.Name).ToArray())}));")
                    .DecrementIndent();
            }
        }
    }

    private void Create(
        IDbFunction function,
        string functionsVariable,
        CSharpRuntimeAnnotationCodeGeneratorParameters parameters)
    {
        if (function.Translation != null)
        {
            throw new InvalidOperationException(RelationalStrings.CompiledModelFunctionTranslation(function.Name));
        }

        AddNamespace(function.ReturnType, parameters.Namespaces);

        var code = Dependencies.CSharpHelper;
        var functionVariable = code.Identifier(
            function.MethodInfo?.Name ?? function.Name, function, parameters.ScopeObjects, capitalize: false);
        var mainBuilder = parameters.MainBuilder;
        mainBuilder
            .Append("var ").Append(functionVariable).AppendLine(" = new RuntimeDbFunction(").IncrementIndent()
            .Append(code.Literal(function.ModelName)).AppendLine(",")
            .Append(parameters.TargetName).AppendLine(",")
            .Append(code.Literal(function.ReturnType)).AppendLine(",")
            .Append(code.Literal(function.Name));

        if (function.Schema != null)
        {
            mainBuilder.AppendLine(",")

View on GitHub (pinned to 3a2006ef56)