{"record":{"id":"1a9f21f44f43cfa5","repo":"dotnet/efcore","slug":"input-parameter-parameter-of-update-stored-pro","errorCode":null,"errorMessage":"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().","messagePattern":"Input parameter '(.+?)' of update stored procedure '(.+?)' is mapped to property '(.+?)' of entity type '(.+?)', but that property is configured with AfterSaveBehavior '(.+?)', and so cannot be saved on update\\. You may need to use HasOriginalValueParameter\\(\\) instead of HasParameter\\(\\)\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs","lineNumber":758,"sourceCode":"                        {\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,\n                                            entityType.DisplayName(),\n                                            property.GetAfterSaveBehavior()));\n                                }\n\n                                break;\n\n                            case StoreObjectType.DeleteStoredProcedure:\n                                break;\n\n                            default:\n                                Check.DebugFail(\"Unexpected stored procedure type: \" + storeObjectIdentifier.StoreObjectType);\n                                break;\n                        }\n                    }","sourceCodeStart":740,"sourceCodeEnd":776,"githubUrl":"https://github.com/dotnet/efcore/blob/dbf9771522148d61a2467854921bd5dc6f6e6916/src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs#L740-L776","documentation":"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.","triggerScenarios":"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.","commonSituations":"Marking a property read-only but still binding it as an update param; intending original-value semantics but using HasParameter.","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."],"exampleFix":"// before\nmodelBuilder.Entity<Blog>().Property(b => b.CreatedAt).Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Throw);\nsp.HasParameter(\"CreatedAt\"); // update input param\n\n// after\nsp.HasOriginalValueParameter(\"CreatedAt\");\n// or, if it should be writable:\nmodelBuilder.Entity<Blog>().Property(b => b.CreatedAt).Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Save);","handlingStrategy":"validation","validationCode":"foreach (var et in modelBuilder.Model.GetEntityTypes())\n{\n    var upd = et.GetUpdateStoredProcedure();\n    if (upd == null) continue;\n    foreach (var p in upd.Parameters.Where(p => p.PropertyName != null && p.ForOriginalValue != true && p.Direction.HasFlag(System.Data.ParameterDirection.Input)))\n    {\n        var prop = et.FindProperty(p.PropertyName);\n        if (prop != null && prop.GetAfterSaveBehavior() != PropertySaveBehavior.Save)\n            throw new InvalidOperationException($\"{p.Name} maps to non-Save AfterSaveBehavior property\");\n    }\n}","typeGuard":null,"tryCatchPattern":"try { _ = ctx.Model; } catch (InvalidOperationException ex) when (ex.Message.Contains(\"cannot be saved on update\")) { /* set AfterSaveBehavior.Save or switch to HasOriginalValueParameter */ }","preventionTips":["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."],"tags":["ef-core","stored-procedures","parameters","update","save-behavior","model-validation"],"analyzedSha":"dbf9771522148d61a2467854921bd5dc6f6e6916","analyzedAt":"2026-08-06T20:46:03.226Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}