{"record":{"id":"e6465e4bd17a209e","repo":"elsa-workflows/elsa-core","slug":"no-alteration-log-found-in-the-transient-properties","errorCode":null,"errorMessage":"No alteration log found in the transient properties.","messagePattern":"No alteration log found in the transient properties\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/modules/Elsa.Alterations/Middleware/Workflows/RunAlterationsMiddleware.cs","lineNumber":21,"sourceCode":"using Elsa.Alterations.Core.Models;\nusing Elsa.Extensions;\nusing Elsa.Workflows;\nusing Elsa.Workflows.Pipelines.WorkflowExecution;\n\nnamespace Elsa.Alterations.Middleware.Workflows;\n\n/// <summary>\n/// Middleware that runs alterations.\n/// </summary>\ninternal class RunAlterationsMiddleware(WorkflowMiddlewareDelegate next, IEnumerable<IAlterationHandler> handlers) : WorkflowExecutionMiddleware(next)\n{\n    public static readonly object AlterationsPropertyKey = new();\n    public static readonly object AlterationsLogPropertyKey = new();\n\n    public override async ValueTask InvokeAsync(WorkflowExecutionContext context)\n    {\n        var alterations = (IEnumerable<IAlteration>)(context.TransientProperties.GetValue(AlterationsPropertyKey) ?? throw new InvalidOperationException(\"No alterations found in the transient properties.\"));\n        var log = (AlterationLog)(context.TransientProperties.GetValue(AlterationsLogPropertyKey) ?? throw new InvalidOperationException(\"No alteration log found in the transient properties.\"));\n        await RunAsync(context, alterations, log, context.CancellationToken);\n    }\n\n    private async Task RunAsync(WorkflowExecutionContext workflowExecutionContext, IEnumerable<IAlteration> alterations, AlterationLog log, CancellationToken cancellationToken = default)\n    {\n        var commitActions = new List<Func<Task>>();\n\n        foreach (var alteration in alterations)\n        {\n            // Find handlers.\n            var supportedHandlers = handlers.Where(x => x.CanHandle(alteration)).ToList();\n\n            foreach (var handler in supportedHandlers)\n            {\n                // Execute handler.\n                var alterationContext = new AlterationContext(alteration, workflowExecutionContext, log, cancellationToken);\n                await handler.HandleAsync(alterationContext);\n","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.Alterations/Middleware/Workflows/RunAlterationsMiddleware.cs#L3-L39","documentation":"Same middleware as the alterations error, but this one fires when the AlterationsLogPropertyKey entry is missing from TransientProperties. The middleware needs an AlterationLog to record what each alteration did, so it throws InvalidOperationException when the log was not seeded alongside the alterations.","triggerScenarios":"Running a workflow with RunAlterationsMiddleware while TransientProperties contains AlterationsPropertyKey but not AlterationsLogPropertyKey — i.e., the caller seeded the alterations but forgot the log (or seeded them at different pipeline stages).","commonSituations":"Manually seeding only the alterations key; a custom alteration runner that sets the list but constructs the log lazily after the middleware already checked; partial refactoring where the log seeding line was dropped.","solutions":["Seed both properties together: context.TransientProperties.SetValue(RunAlterationsMiddleware.AlterationsLogPropertyKey, new AlterationLog()) next to the alterations value.","Extract a helper that stages alterations and log in one call to keep them in sync.","Verify against the intended alterations-run API instead of hand-seeding properties.","Check resumed/replayed executions also re-seed the log."],"exampleFix":"// before\ncontext.TransientProperties.SetValue(RunAlterationsMiddleware.AlterationsPropertyKey, alterations);\n\n// after\ncontext.TransientProperties.SetValue(RunAlterationsMiddleware.AlterationsPropertyKey, alterations);\ncontext.TransientProperties.SetValue(RunAlterationsMiddleware.AlterationsLogPropertyKey, new AlterationLog());","handlingStrategy":"type-guard","validationCode":"var hasLog = context.TransientProperties.GetValue(RunAlterationsMiddleware.AlterationsLogPropertyKey) is AlterationLog;\nif (!hasLog) throw new InvalidOperationException(\"Seed an AlterationLog before running the workflow.\");","typeGuard":"bool TryGetAlterationLog(WorkflowExecutionContext ctx, out AlterationLog log)\n{\n    log = ctx.TransientProperties.GetValue(RunAlterationsMiddleware.AlterationsLogPropertyKey) as AlterationLog;\n    return log != null;\n}","tryCatchPattern":"try\n{\n    await workflowRunner.RunAsync(workflow, workflowState);\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"No alteration log found in the transient properties\"))\n{\n    logger.LogError(ex, \"Alteration log was not seeded alongside alterations.\");\n}","preventionTips":["Always set AlterationsPropertyKey and AlterationsLogPropertyKey together in one helper.","Construct the AlterationLog up front, even if empty, rather than lazily.","Cover the alteration-run path with a test that asserts both properties are seeded."],"tags":["workflow","alterations","middleware","transient-properties"],"backgroundTag":"internal-invariant-violation","analyzedSha":"fe9217bdfa0e27f0e09e45006eb6898f616e513d","analyzedAt":"2026-09-13T20:32:34.702Z","contentChangedAt":"2026-09-13T20:32:34.702Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}