dotnet/efcore · error · InvalidOperationException
Original value parameter
Error message
Original value parameter '{parameter}' is not allowed on insert stored procedure '{sproc}'. Use HasParameter() instead. What it means
Thrown when a parameter on an Insert stored procedure is configured as an original-value parameter (parameter.ForOriginalValue == true and StoreObjectType == InsertStoredProcedure) at RelationalModelValidator.cs:714-719. Insert operations never read original (pre-save) values — they only write new ones — so HasOriginalValueParameter is meaningless on insert and rejected.
Solutions
- Replace .HasOriginalValueParameter(...) with .HasParameter(...) (current-value/input) in the insert configuration.
- If you need a server-generated value on insert, use .HasResultColumn(...) on a store-generated property instead.
- Keep original-value parameters only on Update and Delete sproc configurations.
Example fix
// before
modelBuilder.Entity<Customer>()
.InsertUsingStoredProcedure("dbo.CustomerInsert", sp =>
{
sp.HasParameter(c => c.Name);
sp.HasOriginalValueParameter(c => c.Id); // throws on insert
});
// after
modelBuilder.Entity<Customer>()
.InsertUsingStoredProcedure("dbo.CustomerInsert", sp =>
{
sp.HasParameter(c => c.Name);
sp.HasResultColumn(c => c.Id); // identity, read back as result
}); Defensive patterns
Strategy: validation
Validate before calling
foreach (var et in modelBuilder.Model.GetEntityTypes())
{
var insert = et.GetInsertStoredProcedure();
if (insert is null) continue;
if (insert.Parameters.Any(p => p.ForOriginalValue == true))
throw new InvalidOperationException($"Insert sproc '{insert.GetStoreIdentifier().DisplayName}' on '{et.Name}' must not have original-value parameters.");
} Try / catch
try { _ = ctx.Model; }
catch (InvalidOperationException ex) when (ex.Message.Contains("not allowed on insert stored procedure"))
{
logger.LogError("Use HasParameter, not HasOriginalValueParameter, on insert. {Msg}", ex.Message);
throw;
} Prevention
- Reserve HasOriginalValueParameter for Update/Delete sproc configs only.
- Write a small Roslyn analyzer or unit test asserting insert sproc parameters are all current-value.
- Don't share a single lambda-based builder across insert/update/delete uniformly.
When it happens
Trigger: Calling .HasOriginalValueParameter(x => x.Foo) inside an .InsertUsingStoredProcedure(... ) configuration block. Usually a copy-paste from an update or delete sproc.
Common situations: Refactoring a shared sproc configuration helper to apply to insert/update/delete uniformly; copy-pasting an update sproc template to an insert sproc; misreading the API surface.
Related errors
- Input parameter ' ' of insert stored procedure ' ' is…
- No property named ' ' found on the entity type ' '…
- Current value parameter
- Both entity type ' ' and ' ' were configured to use ' '…
- No property named ' ' found on the entity type ' '…
AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11).
Data as JSON: /api/errors/f7f626b81999545b.
Report an issue: GitHub.
Appendix: source
Thrown at src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs:716
var originalValueProperties = new Dictionary<string, IProperty>(properties);
var parameterNames = new HashSet<string>();
foreach (var parameter in sproc.Parameters)
{
IProperty? property = null;
if (parameter.PropertyName != null)
{
if (parameter.ForOriginalValue == true)
{
if (!originalValueProperties.TryGetAndRemove(parameter.PropertyName, out property))
{
throw new InvalidOperationException(
RelationalStrings.StoredProcedureParameterNotFound(
parameter.PropertyName, entityType.DisplayName(), storeObjectIdentifier.DisplayName()));
}
if (storeObjectIdentifier.StoreObjectType == StoreObjectType.InsertStoredProcedure)
{
throw new InvalidOperationException(
RelationalStrings.StoredProcedureOriginalValueParameterOnInsert(
parameter.Name, storeObjectIdentifier.DisplayName()));
}
}
else
{
if (!properties.TryGetAndRemove(parameter.PropertyName, out property))
{
throw new InvalidOperationException(
RelationalStrings.StoredProcedureParameterNotFound(
parameter.PropertyName, entityType.DisplayName(), storeObjectIdentifier.DisplayName()));
}
if (storeObjectIdentifier.StoreObjectType == StoreObjectType.DeleteStoredProcedure)
{
throw new InvalidOperationException(
RelationalStrings.StoredProcedureCurrentValueParameterOnDelete(
parameter.Name, storeObjectIdentifier.DisplayName()));View on GitHub (pinned to 3a2006ef56)