{"record":{"id":"7c9d0267b9dd3428","repo":"microsoft/semantic-kernel","slug":"only-one-always-handler-is-allowed-in-a-group-of","errorCode":null,"errorMessage":"Only one `Always` handler is allowed in a group of event handlers.","messagePattern":"Only one `Always` handler is allowed in a group of event handlers\\.","errorType":"exception","errorClass":"KernelException","httpStatus":null,"severity":"error","filePath":"dotnet/src/Experimental/Process.Core/ProcessAgentBuilder.cs","lineNumber":302,"sourceCode":"                    }\n\n                    if (!string.IsNullOrWhiteSpace(condition.Expression))\n                    {\n                        throw new KernelException(\"`Default` handlers must not have an eval expression.\");\n                    }\n\n                    this.DefaultHandler = new DeclarativeEventHandlerBuilder(condition);\n                }\n                else if (condition.Type == DeclarativeProcessConditionType.Eval)\n                {\n                    this.EvalHandlers ??= [];\n                    this.EvalHandlers.Add(new DeclarativeEventHandlerBuilder(condition));\n                }\n                else if (condition.Type == DeclarativeProcessConditionType.Always)\n                {\n                    if (this.DefaultHandler is not null)\n                    {\n                        throw new KernelException(\"Only one `Always` handler is allowed in a group of event handlers.\");\n                    }\n\n                    if (!string.IsNullOrWhiteSpace(condition.Expression))\n                    {\n                        throw new KernelException(\"`Always` handlers must not have an eval expression.\");\n                    }\n\n                    this.AlwaysHandler = new DeclarativeEventHandlerBuilder(condition);\n                }\n                else\n                {\n                    throw new KernelException($\"Unknown condition type: {condition.Type}\");\n                }\n            }\n        }\n    }\n\n    /// <summary>","sourceCodeStart":284,"sourceCodeEnd":320,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/dotnet/src/Experimental/Process.Core/ProcessAgentBuilder.cs#L284-L320","documentation":"Thrown by DeclarativeEventHandlerGroupBuilder constructor when processing a condition of type Always. NOTE: The source code checks 'if (this.DefaultHandler is not null)' but throws the 'Always' message — this is likely a bug; the guard should check AlwaysHandler. In practice, the error fires when a Default handler was already set and an Always condition is subsequently encountered, or (if the bug is fixed) when two Always conditions exist.","triggerScenarios":"Passing a conditions list that includes at least one Always condition while a Default handler is already registered (due to the current guard checking DefaultHandler). If the guard is corrected to check AlwaysHandler, this would fire on duplicate Always conditions instead.","commonSituations":"Defining handler conditions in YAML or code that include both a Default and an Always condition in the same group. Including two Always conditions. The misleading guard makes this error appear in surprising situations where the user intended one Default + one Always, which should be valid.","solutions":["Ensure at most one Always condition exists in the handler group and no conflicting Default handler has been registered before it.","Reorder conditions so that Always comes before Default (workaround for the current DefaultHandler-guard behavior), or avoid mixing Default and Always in the same group until the guard bug is fixed.","Report the guard bug upstream: the Always branch should check AlwaysHandler, not DefaultHandler."],"exampleFix":"// before — Default registered first, then Always triggers the guard\nvar conditions = new List<DeclarativeProcessCondition>\n{\n    new() { Type = DeclarativeProcessConditionType.Default },\n    new() { Type = DeclarativeProcessConditionType.Always } // throws due to guard checking DefaultHandler\n};\n\n// after — only one of Default or Always per group, or reorder so Always is first\nvar conditions = new List<DeclarativeProcessCondition>\n{\n    new() { Type = DeclarativeProcessConditionType.Always }\n};","handlingStrategy":"validation","validationCode":"public static void ValidateAlwaysCondition(List<DeclarativeProcessCondition> conditions)\n{\n    var alwaysCount = conditions.Count(c => c?.Type == DeclarativeProcessConditionType.Always);\n    if (alwaysCount > 1)\n    {\n        throw new KernelException(\"Only one Always handler is allowed per group.\");\n    }\n    // Workaround for the current guard bug: avoid mixing Default and Always\n    var hasDefault = conditions.Any(c => c?.Type == DeclarativeProcessConditionType.Default);\n    var hasAlways = conditions.Any(c => c?.Type == DeclarativeProcessConditionType.Always);\n    if (hasDefault && hasAlways)\n    {\n        // Current implementation throws due to DefaultHandler check in Always branch.\n        throw new KernelException(\"Mixing Default and Always in one group triggers a known guard bug.\");\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep at most one Always condition per handler group.","Until the guard bug is fixed, avoid mixing Default and Always conditions in the same group, or place Always before Default in the list.","Report the upstream bug: the Always branch should check AlwaysHandler, not DefaultHandler."],"tags":["semantic-kernel","process-framework","declarative","event-handlers","validation","possible-bug"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}