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

  1. Add a complete 'agent' block to the declarative node so node.Agent is non-null.
  2. If the node is meant to be the terminal step, set its Id to 'End' (case-insensitive) which needs no agent.
  3. 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

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


AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13). Data as JSON: /api/errors/71a032b636be8ec3. Report an issue: GitHub.