dotnet/efcore · error · InvalidOperationException

Input parameter '{parameter}' of insert stored procedure '{s

Error message

Input parameter '{parameter}' of insert stored procedure '{sproc}' is mapped to property '{property}' of entity type '{entityType}', but that property is configured with BeforeSaveBehavior '{behavior}', and so cannot be saved on insert.

What it means

Thrown when an insert input parameter is mapped to a property whose BeforeSaveBehavior is not Save. Properties that are ignored or throw on insert cannot be persisted during an insert. The validator requires property.GetBeforeSaveBehavior() == PropertySaveBehavior.Save for any insert input parameter.

Source

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

                            RelationalStrings.StoredProcedureParameterNotFound(
                                parameter.PropertyName, entityType.DisplayName(), storeObjectIdentifier.DisplayName()));
                    }

                    if (storeObjectIdentifier.StoreObjectType == StoreObjectType.DeleteStoredProcedure)
                    {
                        throw new InvalidOperationException(
                            RelationalStrings.StoredProcedureCurrentValueParameterOnDelete(
                                parameter.Name, storeObjectIdentifier.DisplayName()));
                    }

                    if (parameter.Direction.HasFlag(ParameterDirection.Input))
                    {
                        switch (storeObjectIdentifier.StoreObjectType)
                        {
                            case StoreObjectType.InsertStoredProcedure:
                                if (property.GetBeforeSaveBehavior() != PropertySaveBehavior.Save)
                                {
                                    throw new InvalidOperationException(
                                        RelationalStrings.StoredProcedureInputParameterForInsertNonSaveProperty(
                                            parameter.Name,
                                            storeObjectIdentifier.DisplayName(),
                                            parameter.PropertyName,
                                            entityType.DisplayName(),
                                            property.GetBeforeSaveBehavior()));
                                }

                                break;

                            case StoreObjectType.UpdateStoredProcedure:
                                if (property.GetAfterSaveBehavior() != PropertySaveBehavior.Save)
                                {
                                    throw new InvalidOperationException(
                                        RelationalStrings.StoredProcedureInputParameterForUpdateNonSaveProperty(
                                            parameter.Name,
                                            storeObjectIdentifier.DisplayName(),
                                            parameter.PropertyName,

View on GitHub (pinned to dbf9771522)

Solutions

  1. Set the property's BeforeSaveBehavior to Save so it can be written on insert.
  2. Remove the input parameter if the property should not be saved on insert.
  3. If the value is store-generated, use a result column instead of an input parameter.

Example fix

// before
modelBuilder.Entity<Blog>().Property(b => b.CreatedAt).Metadata.SetBeforeSaveBehavior(PropertySaveBehavior.Ignore);
sp.HasParameter("CreatedAt"); // insert input param

// after
modelBuilder.Entity<Blog>().Property(b => b.CreatedAt).Metadata.SetBeforeSaveBehavior(PropertySaveBehavior.Save);
sp.HasParameter("CreatedAt");
Defensive patterns

Strategy: validation

Validate before calling

foreach (var et in modelBuilder.Model.GetEntityTypes())
{
    var ins = et.GetInsertStoredProcedure();
    if (ins == null) continue;
    foreach (var p in ins.Parameters.Where(p => p.PropertyName != null && p.ForOriginalValue != true && p.Direction.HasFlag(System.Data.ParameterDirection.Input)))
    {
        var prop = et.FindProperty(p.PropertyName);
        if (prop != null && prop.GetBeforeSaveBehavior() != PropertySaveBehavior.Save)
            throw new InvalidOperationException($"{p.Name} maps to non-Save BeforeSaveBehavior property");
    }
}

Try / catch

try { _ = ctx.Model; } catch (InvalidOperationException ex) when (ex.Message.Contains("cannot be saved on insert")) { /* set BeforeSaveBehavior.Save or remove the param */ }

Prevention

When it happens

Trigger: Mapping a property configured with .BeforeSave(PropertySaveBehavior.Ignore) (or a value generated on add) to an insert input parameter; treating an after-save/computed property as writable on insert.

Common situations: Setting BeforeSaveBehavior.Ignore on a property but still binding it as an insert sproc parameter; mismatch between ValueGenerated and parameter mapping.

Related errors


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