microsoft/semantic-kernel · error · KernelException

External message channel not configured for step with topic

Error message

External message channel not configured for step with topic {processEventData.ExternalTopicName}

What it means

Thrown by KernelProcessStepExternalContext.EmitExternalEventAsync when no IExternalKernelProcessMessageChannel was injected into the context. The context's _externalMessageChannel field is null because the constructor was called with a null channel argument (the default). The framework cannot route the event to an external bus (e.g., Service Bus, SignalR) without a configured channel.

Source

Thrown at dotnet/src/Experimental/Process.Abstractions/KernelProcessStepExternalContext.cs:34

    /// </summary>
    /// <param name="externalMessageChannel">An instance of <see cref="IExternalKernelProcessMessageChannel"/></param>
    public KernelProcessStepExternalContext(IExternalKernelProcessMessageChannel? externalMessageChannel = null)
    {
        this._externalMessageChannel = externalMessageChannel;
    }

    /// <summary>
    /// Emit an external event to through a <see cref="IExternalKernelProcessMessageChannel"/>
    /// component if connected from within the SK process
    /// </summary>
    /// <param name="processEventData">data containing event details</param>
    /// <returns></returns>
    /// <exception cref="KernelException"></exception>
    public async Task EmitExternalEventAsync(KernelProcessProxyMessage processEventData)
    {
        if (this._externalMessageChannel == null)
        {
            throw new KernelException($"External message channel not configured for step with topic {processEventData.ExternalTopicName}");
        }

        await this._externalMessageChannel.EmitExternalEventAsync(processEventData.ExternalTopicName, processEventData).ConfigureAwait(false);
    }

    /// <summary>
    /// Closes connection with external messaging channel
    /// </summary>
    /// <returns><see cref="Task"/></returns>
    /// <exception cref="KernelException"></exception>
    public async Task CloseExternalEventChannelAsync()
    {
        if (this._externalMessageChannel == null)
        {
            throw new KernelException("External message channel not configured for step");
        }

        await this._externalMessageChannel.Uninitialize().ConfigureAwait(false);

View on GitHub (pinned to c028a0c7dc)

Solutions

  1. Register an IExternalKernelProcessMessageChannel implementation with your process runtime so that KernelProcessStepExternalContext is constructed with a non-null channel.
  2. Verify that the proxy step added via ProcessBuilder.AddProxyStep is accompanied by a matching external channel registration in the kernel/process host configuration.
  3. If the step should not emit externally, remove the call to EmitExternalEventAsync or guard it by checking whether the external context has a configured channel before invoking.
  4. Check that the KernelProcess is started through the process runtime that injects external channels (e.g., KernelProcessFunctionExecution or the process runtime extension), not a bare step activation.

Example fix

// before
var context = new KernelProcessStepExternalContext(); // no channel
await context.EmitExternalEventAsync(message); // throws

// after
IExternalKernelProcessMessageChannel channel = new MyMessageChannel();
var context = new KernelProcessStepExternalContext(channel);
await context.EmitExternalEventAsync(message);
Defensive patterns

Strategy: validation

Validate before calling

// Before emitting, check if the external context has a channel configured.
// Note: _externalMessageChannel is private; callers should track whether a channel
// was provided at construction time.
public bool HasExternalChannel(KernelProcessStepExternalContext ctx)
{
    // No public API exposes this; you must track it at the process-host level.
    // Ensure your IExternalKernelProcessMessageChannel is registered before process start.
    return _externalChannelIsRegistered;
}

Try / catch

try
{
    await context.EmitExternalEventAsync(message);
}
catch (KernelException ex) when (ex.Message.Contains("External message channel not configured"))
{
    _logger.LogWarning("External channel not configured; skipping external emit for topic {Topic}", message.ExternalTopicName);
}

Prevention

When it happens

Trigger: A KernelProcessStepContext or KernelProcessStepExternalContext is created without passing an IExternalKernelProcessMessageChannel instance, and then EmitExternalEventAsync is called at runtime (typically from within a KernelProcessStep that tries to emit an event externally via the proxy step's external topic).

Common situations: Running a process that contains an AddProxyStep but the external message channel was not registered with the kernel or process runtime. Migrating from an older SK version where external channels were optional. Unit-testing a step in isolation without wiring up the external channel infrastructure. Forgetting to call kernelBuilder.WithExternalMessageChannel() (or equivalent setup) before starting the process.

Related errors


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