microsoft/semantic-kernel · error · InvalidOperationException
A message targeting function
Error message
A message targeting function '{message.FunctionName}' has resulted in a function named '{invocableFunctions.First()}' becoming invocable. Are the function names configured correctly? What it means
Thrown as InvalidOperationException by LocalStep.HandleMessageAsync when a message targets function X, but after assigning its inputs, a different function Y becomes fully invocable (all its required parameters are present). The framework enforces that a message for one function should not inadvertently complete the inputs of another function, which indicates the function names on edges do not match the step's actual function names.
Solutions
- Ensure the FunctionName on every edge's KernelProcessFunctionTarget matches a [KernelFunction] method name on the target step exactly.
- Check for case-sensitivity issues in function names (e.g., 'process' vs 'Process').
- If two functions share parameter names, rename parameters or functions to avoid ambiguity in input channel resolution.
- Inspect the FindInputChannels logic to verify parameter-to-function mapping is unambiguous.
Example fix
// before - edge targets 'ProcessData' but step method is 'HandleData'
edge.OutputTarget = new KernelProcessFunctionTarget { FunctionName = "ProcessData" };
[KernelFunction] public void HandleData(string input) { }
// after - names match
edge.OutputTarget = new KernelProcessFunctionTarget { FunctionName = "HandleData" }; Defensive patterns
Strategy: validation
Validate before calling
// Validate that edge FunctionNames match actual KernelFunction method names on the step type
var functionNames = typeof(MyStep).GetMethods()
.Where(m => m.GetCustomAttribute<KernelFunctionAttribute>() != null)
.Select(m => m.Name).ToHashSet();
foreach (var edgeList in process.Edges.Values)
{
foreach (var edge in edgeList)
{
if (edge.OutputTarget is KernelProcessFunctionTarget ft && ft.StepId == myStepId)
{
if (!functionNames.Contains(ft.FunctionName)) { /* configuration error */ }
}
}
} Prevention
- Keep edge FunctionName values in sync with [KernelFunction] method names on step classes.
- Run a validation pass that reflects on step types and checks edge targets before StartAsync.
- Avoid giving two functions overlapping parameter names that could cause cross-invocation.
When it happens
Trigger: A message with FunctionName='A' is processed, and after AssignStepFunctionParameterValues merges the values, the invocableFunctions list contains only 'B' (not 'A'). The FirstOrDefault match on message.FunctionName fails, triggering the throw.
Common situations: An edge targets function 'ProcessData' but the step's method is named 'HandleData'; renaming a step's [KernelFunction] method without updating edge targets; case mismatch in function names; multiple functions sharing parameter names so that a message for one fills another's inputs.
Related errors
- Function not found in plugin
- Attempt to build a workflow node from step with no Id
- External message channel not configured for step
- External message channel not configured for step with topic
- Failed to process edge type.
AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13).
Data as JSON: /api/errors/63819431de865108.
Report an issue: GitHub.
Appendix: source
Thrown at dotnet/src/Experimental/Process.LocalRuntime/LocalStep.cs:225
}
// Add the message values to the inputs for the function
this.AssignStepFunctionParameterValues(message);
// If we're still waiting for inputs on all of our functions then don't do anything.
List<string> invocableFunctions = this._inputs.Where(i => i.Value != null && i.Value.All(v => v.Value != null)).Select(i => i.Key).ToList();
var missingKeys = this._inputs.Where(i => i.Value is null || i.Value.Any(v => v.Value is null));
if (invocableFunctions.Count == 0)
{
string missingKeysLog() => string.Join(", ", missingKeys.Select(k => $"{k.Key}: {string.Join(", ", k.Value?.Where(v => v.Value == null).Select(v => v.Key) ?? [])}"));
this._logger.LogDebug("No invocable functions, missing keys: {MissingKeys}", missingKeysLog());
return;
}
// A message can only target one function and should not result in a different function being invoked.
var targetFunction = invocableFunctions.FirstOrDefault((name) => name == message.FunctionName) ??
throw new InvalidOperationException($"A message targeting function '{message.FunctionName}' has resulted in a function named '{invocableFunctions.First()}' becoming invocable. Are the function names configured correctly?");
this._logger.LogDebug("Step with Id `{StepId}` received all required input for function [{TargetFunction}] and is executing.", this.Name, targetFunction);
// Concat all the inputs and run the function
KernelArguments arguments = new(this._inputs[targetFunction]!);
if (!this._functions.TryGetValue(targetFunction, out KernelFunction? function) || function == null)
{
throw new ArgumentException($"Function {targetFunction} not found in plugin {this.Name}");
}
// Invoke the function, catching all exceptions that it may throw, and then post the appropriate event.
#pragma warning disable CA1031 // Do not catch general exception types
try
{
// TODO: Process edges for the OnStepEnter event: This feels like a good use for filters in the non-declarative version
FunctionResult invokeResult = await this.InvokeFunction(function, this._kernel, arguments).ConfigureAwait(false);
this.EmitEvent(View on GitHub (pinned to c028a0c7dc)