dotnet/efcore · error · InvalidOperationException
Input parameter '{parameter}' of update stored procedure '{s
Error message
Input parameter '{parameter}' of update stored procedure '{sproc}' is mapped to property '{property}' of entity type '{entityType}', but that property is configured with AfterSaveBehavior '{behavior}', and so cannot be saved on update. You may need to use HasOriginalValueParameter() instead of HasParameter(). What it means
Thrown when an update input parameter is mapped to a property whose AfterSaveBehavior is not Save. Read-only-after-save properties (e.g. computed or throw-on-update) cannot be persisted during an update. If the original value is what you need (for a concurrency token), use HasOriginalValueParameter instead. The validator requires AfterSaveBehavior == Save for update input parameters.
Source
Thrown at src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs:758
{
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,
entityType.DisplayName(),
property.GetAfterSaveBehavior()));
}
break;
case StoreObjectType.DeleteStoredProcedure:
break;
default:
Check.DebugFail("Unexpected stored procedure type: " + storeObjectIdentifier.StoreObjectType);
break;
}
}View on GitHub (pinned to dbf9771522)
Solutions
- Set the property's AfterSaveBehavior to Save if it should be writable on update.
- Use HasOriginalValueParameter if you want the original (pre-update) value, e.g. for a concurrency token.
- Remove the input parameter if the property should not be saved on update.
Example fix
// before
modelBuilder.Entity<Blog>().Property(b => b.CreatedAt).Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Throw);
sp.HasParameter("CreatedAt"); // update input param
// after
sp.HasOriginalValueParameter("CreatedAt");
// or, if it should be writable:
modelBuilder.Entity<Blog>().Property(b => b.CreatedAt).Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Save); Defensive patterns
Strategy: validation
Validate before calling
foreach (var et in modelBuilder.Model.GetEntityTypes())
{
var upd = et.GetUpdateStoredProcedure();
if (upd == null) continue;
foreach (var p in upd.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.GetAfterSaveBehavior() != PropertySaveBehavior.Save)
throw new InvalidOperationException($"{p.Name} maps to non-Save AfterSaveBehavior property");
}
} Try / catch
try { _ = ctx.Model; } catch (InvalidOperationException ex) when (ex.Message.Contains("cannot be saved on update")) { /* set AfterSaveBehavior.Save or switch to HasOriginalValueParameter */ } Prevention
- For concurrency tokens on update, use HasOriginalValueParameter rather than binding a read-only property as a current value.
- Keep AfterSaveBehavior consistent with which parameters reference the property.
When it happens
Trigger: Mapping a property with .AfterSave(PropertySaveBehavior.Throw/Ignore) to an update input parameter; binding a concurrency token as a current-value param when its original value is needed.
Common situations: Marking a property read-only but still binding it as an update param; intending original-value semantics but using HasParameter.
Related errors
- Input parameter '{parameter}' of insert stored procedure '{s
- No property named '{property}' found on the entity type '{en
- Original value parameter '{parameter}' is not allowed on ins
- Current value parameter '{parameter}' is not allowed on dele
- The parameter '{parameter}' cannot be added to the stored pr
AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06).
Data as JSON: /api/errors/1a9f21f44f43cfa5.
Report an issue: GitHub.