{"record":{"id":"809020e0b0b4b2b2","repo":"dotnet/efcore","slug":"input-parameter-parameter-of-insert-stored-pro","errorCode":null,"errorMessage":"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.","messagePattern":"Input parameter '(.+?)' of insert stored procedure '(.+?)' is mapped to property '(.+?)' of entity type '(.+?)', but that property is configured with BeforeSaveBehavior '(.+?)', and so cannot be saved on insert\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs","lineNumber":744,"sourceCode":"                            RelationalStrings.StoredProcedureParameterNotFound(\n                                parameter.PropertyName, entityType.DisplayName(), storeObjectIdentifier.DisplayName()));\n                    }\n\n                    if (storeObjectIdentifier.StoreObjectType == StoreObjectType.DeleteStoredProcedure)\n                    {\n                        throw new InvalidOperationException(\n                            RelationalStrings.StoredProcedureCurrentValueParameterOnDelete(\n                                parameter.Name, storeObjectIdentifier.DisplayName()));\n                    }\n\n                    if (parameter.Direction.HasFlag(ParameterDirection.Input))\n                    {\n                        switch (storeObjectIdentifier.StoreObjectType)\n                        {\n                            case StoreObjectType.InsertStoredProcedure:\n                                if (property.GetBeforeSaveBehavior() != PropertySaveBehavior.Save)\n                                {\n                                    throw new InvalidOperationException(\n                                        RelationalStrings.StoredProcedureInputParameterForInsertNonSaveProperty(\n                                            parameter.Name,\n                                            storeObjectIdentifier.DisplayName(),\n                                            parameter.PropertyName,\n                                            entityType.DisplayName(),\n                                            property.GetBeforeSaveBehavior()));\n                                }\n\n                                break;\n\n                            case StoreObjectType.UpdateStoredProcedure:\n                                if (property.GetAfterSaveBehavior() != PropertySaveBehavior.Save)\n                                {\n                                    throw new InvalidOperationException(\n                                        RelationalStrings.StoredProcedureInputParameterForUpdateNonSaveProperty(\n                                            parameter.Name,\n                                            storeObjectIdentifier.DisplayName(),\n                                            parameter.PropertyName,","sourceCodeStart":726,"sourceCodeEnd":762,"githubUrl":"https://github.com/dotnet/efcore/blob/3a2006ef569de08368d59db5e1468aa8f407e4f8/src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs#L726-L762","documentation":"Thrown in the input-parameter switch for Insert sprocs when the bound property's GetBeforeSaveBehavior() != PropertySaveBehavior.Save (RelationalModelValidator.cs:741-751). Insert input parameters must map to properties that EF will actually save on insert; a property configured with BeforeSaveBehavior.Throw or Ignore cannot be passed as an insert parameter because the value wouldn't be written.","triggerScenarios":"Marking a property .ValueGeneratedOnAdd()/.ValueGeneratedOnAddOrUpdate() (which sets BeforeSaveBehavior to Ignore) and then binding it as an input parameter on the insert sproc via .HasParameter(x => ...). Or explicitly setting .Metadata.SetBeforeSaveBehavior(PropertySaveBehavior.Throw).","commonSituations":"Treating an identity/computed column as both input parameter and result column; setting a column to DB-generated and still passing a value in the insert sproc; scaffolding where computed columns were accidentally wired as input parameters.","solutions":["Remove the HasParameter binding for the store-generated property and use HasResultColumn instead (with .ValueGeneratedOnAdd()).","If you intend to send the value on insert, change BeforeSaveBehavior to Save: .Property(x => x.Foo).ValueGeneratedNever() or .Metadata.SetBeforeSaveBehavior(PropertySaveBehavior.Save).","For an identity PK, let the DB generate it and read it back as a result column rather than as an input parameter."],"exampleFix":"// before — Id is identity but passed as input\nmodelBuilder.Entity<Customer>(b =>\n{\n    b.Property(c => c.Id).ValueGeneratedOnAdd(); // BeforeSaveBehavior = Ignore\n    b.InsertUsingStoredProcedure(\"dbo.CustomerInsert\", sp =>\n    {\n        sp.HasParameter(c => c.Id);   // throws\n        sp.HasParameter(c => c.Name);\n    });\n});\n\n// after\nmodelBuilder.Entity<Customer>(b =>\n{\n    b.Property(c => c.Id).ValueGeneratedOnAdd();\n    b.InsertUsingStoredProcedure(\"dbo.CustomerInsert\", sp =>\n    {\n        sp.HasParameter(c => c.Name);\n        sp.HasResultColumn(c => c.Id); // read generated value back\n    });\n});","handlingStrategy":"validation","validationCode":"foreach (var et in modelBuilder.Model.GetEntityTypes())\n{\n    var insert = et.GetInsertStoredProcedure();\n    if (insert is null) continue;\n    foreach (var p in insert.Parameters)\n    {\n        if (p.ForOriginalValue == true) continue;\n        if (!p.Direction.HasFlag(ParameterDirection.Input)) continue;\n        if (p.PropertyName is null) continue;\n        var prop = et.FindProperty(p.PropertyName);\n        if (prop is not null && prop.GetBeforeSaveBehavior() != PropertySaveBehavior.Save)\n            throw new InvalidOperationException($\"Insert sproc input parameter '{p.Name}' maps to '{et.Name}.{p.PropertyName}' whose BeforeSaveBehavior is {prop.GetBeforeSaveBehavior()} (not Save).\");\n    }\n}","typeGuard":null,"tryCatchPattern":"try { _ = ctx.Model; }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"cannot be saved on insert\"))\n{\n    logger.LogError(\"Insert input parameter maps to a non-savable property. {Msg}\", ex.Message);\n    throw;\n}","preventionTips":["For identity/computed columns, use HasResultColumn + ValueGeneratedOnAdd instead of HasParameter on insert.","Set BeforeSaveBehavior to Save only for properties you genuinely write on insert.","Audit insert sproc configs after changing a property's ValueGenerated setting."],"tags":["efcore","relational","stored-procedure","parameter","insert","before-save-behavior","store-generated","model-validation"],"backgroundTag":null,"analyzedSha":"3a2006ef569de08368d59db5e1468aa8f407e4f8","analyzedAt":"2026-08-11T23:42:04.146Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}