dotnet/efcore · error · InvalidOperationException

'IsNullable' cannot be set on DbFunction

Error message

'IsNullable' cannot be set on DbFunction '{functionName}' since the function does not represent a scalar function.

What it means

Nullability propagation only applies to scalar functions (a single value whose NULL behavior can be configured). SetIsNullable throws when called on a DbFunction whose IsScalar is false — i.e. a table-valued function returning IQueryable<T> — because nullable does not apply to a result set.

Solutions

  1. Remove the nullability configuration (IsNullable / HasNullable) from the TVF DbFunction.
  2. If nullability is required, change the function to return a scalar type so it becomes a scalar DbFunction.

Example fix

// before
public IQueryable<Order> ActiveOrders() => throw new NotSupportedException();
modelBuilder.HasDbFunction(typeof(AppDb).GetMethod(nameof(ActiveOrders)))
    .IsNullable(true);  // throws: TVF

// after
modelBuilder.HasDbFunction(typeof(AppDb).GetMethod(nameof(ActiveOrders)));
// do not configure nullability on a table-valued function
Defensive patterns

Strategy: validation

Validate before calling

var fn = modelBuilder.HasDbFunction(typeof(AppDb).GetMethod(nameof(AppDb.ActiveOrders))!).Metadata;
if (!fn.IsScalar)
{
    // do not call IsNullable / SetIsNullable on this function
    return;
}

Type guard

static bool CanConfigureNullability(IReadOnlyDbFunction fn) => fn.IsScalar;

Prevention

When it happens

Trigger: Calling HasDbFunction(...).CanBeNull / SetIsNullable / builder.IsNullable() on a TVF (method returning IQueryable<T>); common when copy-pasting scalar-function configuration onto a composable TVF.

Common situations: Reusing a fluent configuration block for a scalar function on a TVF; refactor converting a scalar function to a TVF without removing the nullability configuration.

Related errors


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

Appendix: source

Thrown at src/EFCore.Relational/Metadata/Internal/DbFunction.cs:476

    public virtual bool IsNullable
    {
        get => _nullable;
        set => SetIsNullable(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 bool SetIsNullable(bool nullable, ConfigurationSource configurationSource)
    {
        EnsureMutable();

        if (!IsScalar)
        {
            throw new InvalidOperationException(RelationalStrings.NonScalarFunctionCannotBeNullable(Name));
        }

        _nullable = nullable;
        _nullableConfigurationSource = configurationSource.Max(_nullableConfigurationSource);

        return nullable;
    }

    /// <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? GetIsNullableConfigurationSource()
        => _nullableConfigurationSource;

    /// <summary>

View on GitHub (pinned to 3a2006ef56)