dotnet/efcore · error · InvalidOperationException

The property '{entityType}.{property}' is mapped to an outpu

Error message

The property '{entityType}.{property}' is mapped to an output parameter of the stored procedure '{sproc}', but it is not configured as store-generated. Either configure it as store-generated or don't configure the parameter as output.

What it means

Thrown during model validation when an Insert/Update stored procedure maps a property to an output (or input-output) parameter, but that property is not configured as store-generated (ValueGenerated). EF uses output parameters to read back values the database generates (e.g. identity/computed columns), so an output parameter on a non-generated property is meaningless and almost always a configuration mistake. The validator at line 796-811 checks `parameter.Direction != ParameterDirection.Input` and requires the property be in the storeGenerated set.

Source

Thrown at src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs:808

            }

            switch (storeObjectIdentifier.StoreObjectType)
            {
                case StoreObjectType.InsertStoredProcedure:
                case StoreObjectType.UpdateStoredProcedure:
                    if (parameter.Direction != ParameterDirection.Input
                        && !storeGeneratedProperties.Remove(property!.Name))
                    {
                        if (sproc.Parameters.Any(p => p.PropertyName == property.Name
                                && p.ForOriginalValue != parameter.ForOriginalValue
                                && p.Direction != ParameterDirection.Input))
                        {
                            throw new InvalidOperationException(
                                RelationalStrings.StoredProcedureOutputParameterConflict(
                                    entityType.DisplayName(), parameter.PropertyName, storeObjectIdentifier.DisplayName()));
                        }

                        throw new InvalidOperationException(
                            RelationalStrings.StoredProcedureOutputParameterNotGenerated(
                                entityType.DisplayName(), parameter.PropertyName, storeObjectIdentifier.DisplayName()));
                    }

                    break;
                case StoreObjectType.DeleteStoredProcedure:
                    if (!property!.IsPrimaryKey()
                        && !property.IsConcurrencyToken)
                    {
                        throw new InvalidOperationException(
                            RelationalStrings.StoredProcedureDeleteNonKeyProperty(
                                entityType.DisplayName(), parameter.PropertyName, storeObjectIdentifier.DisplayName()));
                    }

                    break;
                default:
                    Check.DebugFail("Unexpected stored procedure type: " + storeObjectIdentifier.StoreObjectType);
                    break;

View on GitHub (pinned to dbf9771522)

Solutions

  1. Mark the property as store-generated, e.g. propertyBuilder.ValueGeneratedOnAdd() or .HasComputedColumnSql("...").
  2. If the value is not database-generated, change the parameter direction to input-only by using .Parameter(...) instead of .OutputParameter(...)/.InputOutputParameter(...).
  3. Remove the parameter mapping entirely if the sproc does not actually return that value.

Example fix

// before
modelBuilder.Entity<Order>()
    .InsertStoredProcedure(o => o
        .Parameter(p => p.Status, "status")
        .OutputParameter(p => p.Status, "status_out")); // Status is not store-generated

// after - make it input only since Status is set by the client
modelBuilder.Entity<Order>()
    .InsertStoredProcedure(o => o
        .Parameter(p => p.Status, "status"));
// OR mark it generated:
// modelBuilder.Entity<Order>().Property(p => p.Status).ValueGeneratedOnAdd();
Defensive patterns

Strategy: validation

Validate before calling

// Before finalizing the model, ensure each output/inputOutput parameter
// on an Insert/Update sproc targets a store-generated property.
foreach (var et in modelBuilder.Model.GetEntityTypes())
{
    foreach (var sproc in et.GetStoredProcedures())
    {
        if (sproc.StoreObjectType is StoreObjectType.InsertStoredProcedure
                                  or StoreObjectType.UpdateStoredProcedure)
        {
            var generated = et.GetProperties()
                .Where(p => p.ValueGenerated != ValueGenerated.Never)
                .Select(p => p.Name).ToHashSet();
            foreach (var param in sproc.Parameters)
            {
                if (param.Direction != ParameterDirection.Input
                    && param.PropertyName is string name
                    && !generated.Contains(name))
                {
                    throw new InvalidOperationException(
                        $"Output param '{param.Name}' on {et.Name} maps non-generated property '{name}'.");
                }
            }
        }
    }
}

Prevention

When it happens

Trigger: Calling `.InsertStoredProcedure(...)` or `.UpdateStoredProcedure(...)` on an entity and using `.OutputParameter()` / `.InputOutputParameter()` for a property that has no `.ValueGeneratedOnAdd()` / `.ValueGeneratedOnUpdate()` / `.HasComputedColumnSql()` configuration. The check fires for InsertStoredProcedure and UpdateStoredProcedure store object types only.

Common situations: Developer maps every column to an output parameter by habit; copy-pasting a parameter list from a SQL sproc signature into EF config without marking computed/identity columns; switching a property from database-generated to client-set but forgetting to drop the output parameter mapping.

Related errors


AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06). Data as JSON: /api/errors/75fcef21dd6ddf4a. Report an issue: GitHub.