microsoft/semantic-kernel · error · KernelException

A step cannot be activated before it has been initialized.

Error message

A step cannot be activated before it has been initialized.

What it means

ActivateStepAsync is the lazy one-time initialization that instantiates the step, loads kernel functions, and sets up input channels. It requires _stepInfo to be non-null, which is set by InitializeStep (called from InitializeStepAsync or OnActivateAsync). If ActivateStepAsync runs before initialization, this KernelException is thrown.

Solutions

  1. Call and await InitializeStepAsync before any method that triggers lazy activation (message processing, state extraction).
  2. Ensure that for re-activated actors, the Dapr state store contains ActorStateKeys.StepInfoState so OnActivateAsync can call InitializeStep.
  3. If the actor is fresh, always initialize first: InitializeStepAsync must be the first call after creating the proxy.

Example fix

// before
var stepProxy = factory.CreateActorProxy<IStep>(stepId, nameof(StepActor));
await stepProxy.ProcessIncomingMessagesAsync(); // triggers lazy activation, throws

// after
var stepProxy = factory.CreateActorProxy<IStep>(stepId, nameof(StepActor));
await stepProxy.InitializeStepAsync(stepInfo, parentProcessId);
await stepProxy.ProcessIncomingMessagesAsync();
Defensive patterns

Strategy: validation

Validate before calling

// Ensure InitializeStepAsync is called before any method that triggers lazy activation:
await stepActor.InitializeStepAsync(stepInfo, parentProcessId);
// Only then call methods that internally trigger _activateTask:
await stepActor.PrepareIncomingMessagesAsync();
await stepActor.ProcessIncomingMessagesAsync();
await stepActor.ToDaprStepInfoAsync();

Try / catch

try
{
    await stepActor.ToDaprStepInfoAsync();
}
catch (KernelException ex) when (ex.Message.Contains("cannot be activated before it has been initialized"))
{
    logger.LogError("Step actor activated before InitializeStepAsync. Call initialization first.");
}

Prevention

When it happens

Trigger: The lazy _activateTask fires (triggered by HandleMessageAsync, ToDaprStepInfoAsync, or PrepareIncomingMessagesAsync) before InitializeStepAsync has been called and before OnActivateAsync found persisted state. The _stepInfo field is still null.

Common situations: A step actor proxy is used without calling InitializeStepAsync first. The actor is re-activated from scratch (no persisted state) and a method triggers lazy activation before initialization. A race between proxy creation and initialization.

Related errors


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

Appendix: source

Thrown at dotnet/src/Experimental/Process.Runtime.Dapr/Actors/StepActor.cs:355

        }
#pragma warning restore CA1031 // Do not catch general exception types
    }

    internal virtual Dictionary<string, Dictionary<string, object?>?> GenerateInitialInputs()
    {
        return this.FindInputChannels(this._functions, this._logger);
    }

    /// <summary>
    /// Initializes the step with the provided step information.
    /// </summary>
    /// <returns>A <see cref="ValueTask"/></returns>
    /// <exception cref="KernelException"></exception>
    protected virtual async ValueTask ActivateStepAsync()
    {
        if (this._stepInfo is null)
        {
            throw new KernelException("A step cannot be activated before it has been initialized.").Log(this._logger);
        }

        // Instantiate an instance of the inner step object
        KernelProcessStep stepInstance = (KernelProcessStep)ActivatorUtilities.CreateInstance(this._kernel.Services, this._innerStepType!);
        var kernelPlugin = KernelPluginFactory.CreateFromObject(stepInstance, pluginName: this._stepInfo.State.Name);

        // Load the kernel functions
        foreach (KernelFunction f in kernelPlugin)
        {
            this._functions.Add(f.Name, f);
        }

        // Initialize the input channels
        this._initialInputs = this.GenerateInitialInputs();
        this._inputs = this._initialInputs.ToDictionary(kvp => kvp.Key, kvp => kvp.Value?.ToDictionary(kvp => kvp.Key, kvp => kvp.Value));

        // Activate the step with user-defined state if needed
        KernelProcessStepState? stateObject = null;

View on GitHub (pinned to c028a0c7dc)