microsoft/semantic-kernel · error · KernelException
Declarative steps must have an agent defined.
Error message
Declarative steps must have an agent defined.
What it means
Thrown by BuildDeclarativeStepAsync when a declarative node (not the built-in 'End' node) has no Agent definition. Declarative steps are backed by an AgentDefinition, so a missing node.Agent is treated as an invalid step definition.
Source
Thrown at dotnet/src/Experimental/Process.Core/Workflow/WorkflowBuilder.cs:135
else
{
throw new ArgumentException($"Unsupported node type: {node.Type}");
}
}
private Task BuildDeclarativeStepAsync(Node node, ProcessBuilder processBuilder)
{
Verify.NotNull(node);
// Check for built-in step types
if (node.Id.Equals("End", StringComparison.OrdinalIgnoreCase))
{
var endBuilder = processBuilder.AddEndStep();
this._stepBuilders["End"] = endBuilder;
return Task.CompletedTask;
}
AgentDefinition? agentDefinition = node.Agent ?? throw new KernelException("Declarative steps must have an agent defined.");
var stepBuilder = processBuilder.AddStepFromAgent(agentDefinition, node.Id);
if (stepBuilder is not ProcessAgentBuilder agentBuilder)
{
throw new KernelException($"Failed to build step from agent definition: {node.Id}");
}
// ########################### Parsing on_complete and on_error conditions ###########################
if (node.OnComplete != null)
{
if (node.OnComplete.Any(c => c is null || c.OnCondition is null))
{
throw new ArgumentException("A complete on_complete condition is required for declarative steps.");
}
agentBuilder.OnComplete([.. node.OnComplete.Select(c => c.OnCondition!)]);
}
View on GitHub (pinned to c028a0c7dc)
Solutions
- Add a complete 'agent' block to the declarative node so node.Agent is non-null.
- If the node is meant to be the terminal step, set its Id to 'End' (case-insensitive) which needs no agent.
- Validate that every non-End declarative node has an agent before building.
Example fix
// before
node.Type = "declarative"; node.Id = "myStep"; node.Agent = null;
// after
node.Agent = new AgentDefinition { Type = "...", /* ... */ }; Defensive patterns
Strategy: validation
Validate before calling
foreach (var n in workflow.Nodes.Where(x => x.Type == "declarative" && !x.Id.Equals("End", StringComparison.OrdinalIgnoreCase)))
if (n.Agent is null) throw new ArgumentException($"Declarative node {n.Id} has no agent."); Type guard
static bool DeclarativeNodeHasAgent(Node n) => n.Id.Equals("End", StringComparison.OrdinalIgnoreCase) || n.Agent is not null; Try / catch
try { await builder.BuildProcessAsync(workflow, yaml); }
catch (KernelException ex) when (ex.Message.Contains("agent defined"))
{ /* add the agent block or use Id=End */ } Prevention
- Require an agent block for every non-End declarative node in authoring templates.
- Run a structural validator over the workflow before building.
- Document the End-step special case for terminal nodes.
When it happens
Trigger: A node with Type 'declarative', an Id other than 'End', and node.Agent == null. The null-coalescing throw fires immediately when reading node.Agent.
Common situations: Declarative workflow YAML that declares a step but omits the 'agent' block; authoring a declarative step without specifying which agent powers it.
Related errors
- Failed to build step from agent definition: {node.Id}
- A complete on_complete condition is required for declarative
- The agent specified in the Node with id {node.Id} is not ful
- Workflow nodes are not specified.
- Workflow inputs are not specified.
AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13).
Data as JSON: /api/errors/71a032b636be8ec3.
Report an issue: GitHub.