microsoft/semantic-kernel · error · KernelException

The target for the edge is not a function target.

Error message

The target for the edge is not a function target.

What it means

EnqueueExternalMessagesAsync processes external KernelProcessEvents sent to the process. For each edge associated with an external event, it requires edge.OutputTarget to be a KernelProcessFunctionTarget so it can resolve the destination step and function. The Dapr runtime at this call site does not handle other KernelProcessTarget subtypes (KernelProcessStateTarget, KernelProcessEmitTarget, KernelProcessAgentInvokeTarget).

Solutions

  1. Ensure that all edges reachable from external events have OutputTarget of type KernelProcessFunctionTarget.
  2. If using state-update or agent-invoke targets, restrict them to edges that are only traversed by internal step-to-step messaging, not by the external-event entry path.
  3. Upgrade the Process.Runtime.Dapr package to a version that supports the additional target types if one is available.
Defensive patterns

Strategy: validation

Validate before calling

// Before building the process, validate that external-event edges only use function targets:
foreach (var edge in processBuilder.Build().Edges)
{
    if (edge.Value.Any(e => e.OutputTarget is not KernelProcessFunctionTarget))
    {
        throw new InvalidOperationException($"Edge for event {edge.Key} has a non-function target, unsupported by Dapr external-event routing.");
    }
}

Type guard

static bool IsFunctionTarget(KernelProcessEdge edge) => edge.OutputTarget is KernelProcessFunctionTarget;

Try / catch

try
{
    await process.StartAsync(keepAlive: true);
}
catch (KernelException ex) when (ex.Message.Contains("not a function target"))
{
    logger.LogError("An external event edge targets a non-function target type. The Dapr runtime only supports KernelProcessFunctionTarget for external events.");
}

Prevention

When it happens

Trigger: An external event is sent to the process whose output edge targets a non-function target type. This occurs when the process graph was built with state-update targets, emit targets, or agent-invocation targets on edges that the external-event path traverses.

Common situations: Using newer Semantic Kernel process features (state targets, agent invoke targets) with the Dapr runtime, which only fully supports KernelProcessFunctionTarget for external event routing. Also occurs from a corrupted or hand-crafted process graph where OutputTarget is set to an unexpected subtype.

Related errors


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

Appendix: source

Thrown at dotnet/src/Experimental/Process.Runtime.Dapr/Actors/ProcessActor.cs:382

    /// <summary>
    /// Processes external events that have been sent to the process, translates them to <see cref="ProcessMessage"/>s, and enqueues
    /// them to the provided message channel so that they can be processed in the next superstep.
    /// </summary>
    private async Task EnqueueExternalMessagesAsync()
    {
        IExternalEventBuffer externalEventQueue = this.ProxyFactory.CreateActorProxy<IExternalEventBuffer>(new ActorId(this.Id.GetId()), nameof(ExternalEventBufferActor));
        IList<string> dequeuedEvents = await externalEventQueue.DequeueAllAsync().ConfigureAwait(false);
        IList<KernelProcessEvent> externalEvents = dequeuedEvents.ToKernelProcessEvents();

        foreach (KernelProcessEvent externalEvent in externalEvents)
        {
            if (this._outputEdges!.TryGetValue(externalEvent.Id!, out List<KernelProcessEdge>? edges) && edges is not null)
            {
                foreach (KernelProcessEdge edge in edges)
                {
                    if (edge.OutputTarget is not KernelProcessFunctionTarget functionTarget)
                    {
                        throw new KernelException("The target for the edge is not a function target.").Log(this._logger);
                    }

                    ProcessMessage message = ProcessMessageFactory.CreateFromEdge(edge, externalEvent.Id, externalEvent.Data);
                    var scopedMessageBufferId = this.ScopedActorId(new ActorId(functionTarget.StepId));
                    var messageQueue = this.ProxyFactory.CreateActorProxy<IMessageBuffer>(scopedMessageBufferId, nameof(MessageBufferActor));
                    await messageQueue.EnqueueAsync(message.ToJson()).ConfigureAwait(false);
                }
            }
        }
    }

    /// <summary>
    /// Check for the presence of an global-error event and any edges defined for processing it.
    /// When both exist, the error event is processed and sent to the appropriate targets.
    /// </summary>
    private async Task HandleGlobalErrorMessageAsync()
    {
        var errorEventQueue = this.ProxyFactory.CreateActorProxy<IEventBuffer>(ProcessActor.GetScopedGlobalErrorEventBufferId(this.Id.GetId()), nameof(EventBufferActor));

View on GitHub (pinned to c028a0c7dc)