dotnet/efcore · error · InvalidOperationException

The computed column SQL has not been specified for the…

Error message

The computed column SQL has not been specified for the column '{table}.{column}'. Specify the SQL before using Entity Framework to create the database schema.

What it means

A column flagged as computed must supply its defining SQL. Initialize throws when ComputedColumnSql is the empty string, because EF cannot emit a GENERATED ALWAYS AS clause with no expression.

Solutions

  1. Pass a real expression to HasComputedColumnSql("[Qty] * [Price]").
  2. If the column is not computed, remove the call entirely.
  3. Coerce empty strings to null before assigning ComputedColumnSql.
  4. Verify scaffolder output preserves the expression.

Example fix

// before
builder.Entity<Order>()
    .Property(o => o.Total)
    .HasComputedColumnSql(""); // throws

// after
builder.Entity<Order>()
    .Property(o => o.Total)
    .HasComputedColumnSql("[Qty] * [UnitPrice]");
Defensive patterns

Strategy: validation

Validate before calling

if (!string.IsNullOrEmpty(computedColumnSql))
{
    builder.HasComputedColumnSql(computedColumnSql);
}

Type guard

static bool IsValidComputedColumnSql(string? sql)
    => string.IsNullOrEmpty(sql) || sql.Trim().Length > 0;

Prevention

When it happens

Trigger: A column whose ComputedColumnSql is set to string.Empty during migration diffing; from .HasComputedColumnSql("") or scaffolding/attribute code that yields empty.

Common situations: Calling .HasComputedColumnSql(string.Empty); wiring the SQL from a config value that resolves empty; scaffolding round-trips that drop the expression; conditional builder code assigning empty.

Related errors


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

Appendix: source

Thrown at src/EFCore.Relational/Migrations/Internal/MigrationsModelDiffer.cs:1242

        if (column.DefaultValue == DBNull.Value)
        {
            throw new InvalidOperationException(
                RelationalStrings.DefaultValueUnspecified(
                    column.Table.SchemaQualifiedName,
                    column.Name));
        }

        if (column.DefaultValueSql?.Length == 0)
        {
            throw new InvalidOperationException(
                RelationalStrings.DefaultValueSqlUnspecified(
                    column.Table.SchemaQualifiedName,
                    column.Name));
        }

        if (column.ComputedColumnSql?.Length == 0)
        {
            throw new InvalidOperationException(
                RelationalStrings.ComputedColumnSqlUnspecified(
                    column.Name,
                    column.Table.SchemaQualifiedName));
        }

        var property = column.PropertyMappings.First().Property;
        var valueConverter = GetValueConverter(property, typeMapping);
        columnOperation.ClrType
            = (valueConverter?.ProviderClrType
                ?? typeMapping.ClrType).UnwrapNullableType();

        column.TryGetDefaultValue(out var defaultValue);
        columnOperation.DefaultValue = defaultValue
            ?? (inline || isNullable
                ? null
                : typeMapping.GetDefaultProviderValue());
        columnOperation.DefaultValueSql = column.DefaultValueSql;
        columnOperation.ColumnType = column.StoreType;

View on GitHub (pinned to 3a2006ef56)