The Errors
Semantic Kernel plugin issues produce several different error messages depending on where the failure occurs.
Error 1: Function not found
Microsoft.SemanticKernel.KernelException:
Function 'WeatherPlugin-GetCurrentWeather' not found.
Error 2: Plugin not registered
System.Collections.Generic.KeyNotFoundException:
The given key 'WeatherPlugin' was not present in the dictionary.
Error 3: Runtime invocation failure
Microsoft.SemanticKernel.KernelException:
Error occurred while invoking function 'WeatherPlugin-GetCurrentWeather'.
---> System.InvalidOperationException:
Unable to convert parameter 'temperature' from System.Text.Json.JsonElement to System.Double.
All three errors lead to the same outcome: the kernel cannot call the function you intended. The fix depends on which part of the registration and invocation pipeline broke.
Root Cause 1: Missing [KernelFunction] Attribute
Semantic Kernel does not scan for methods automatically. Only methods decorated with [KernelFunction] are registered. This is the most common mistake, especially for developers coming from frameworks that use convention-based discovery.
Broken:
public class WeatherPlugin
{
// Missing [KernelFunction] — this method is invisible to the kernel
public string GetCurrentWeather(string city)
{
return $"The weather in {city} is 72°F and sunny.";
}
}
Fixed:
using Microsoft.SemanticKernel;
using System.ComponentModel;
public class WeatherPlugin
{
[KernelFunction("GetCurrentWeather")]
[Description("Gets the current weather for a given city")]
public string GetCurrentWeather(
[Description("The city name, e.g. 'Seattle'")] string city)
{
return $"The weather in {city} is 72°F and sunny.";
}
}
The [KernelFunction] attribute is the entry point for discovery. The [Description] attributes are not strictly required for manual invocation, but they are essential for AI function calling — the model reads these descriptions to decide when and how to call the function.
Root Cause 2: Non-Public Methods
Semantic Kernel only discovers public methods. Internal, protected, and private methods are silently skipped during registration. No warning is logged.
Broken:
public class MathPlugin
{
[KernelFunction]
internal double Add(double a, double b) => a + b; // internal — not discovered
}
Fixed:
public class MathPlugin
{
[KernelFunction("Add")]
[Description("Adds two numbers together")]
public double Add(
[Description("First number")] double a,
[Description("Second number")] double b) => a + b;
}
Root Cause 3: Plugin Not Registered with the Kernel
Writing the plugin class is only half the job. You must also add it to the kernel. There are several registration methods, and using the wrong one (or forgetting it entirely) leads to “not found” errors.
Option A: AddFromType (preferred for DI scenarios)
var builder = Kernel.CreateBuilder();
builder.AddAzureOpenAIChatCompletion(deploymentName, endpoint, apiKey);
builder.Plugins.AddFromType<WeatherPlugin>();
var kernel = builder.Build();
This approach lets Semantic Kernel instantiate the plugin. If the plugin class has constructor dependencies, they are resolved from the kernel’s service provider.
Option B: AddFromObject (for pre-built instances)
var weatherPlugin = new WeatherPlugin(httpClient, logger);
var builder = Kernel.CreateBuilder();
builder.AddAzureOpenAIChatCompletion(deploymentName, endpoint, apiKey);
builder.Plugins.AddFromObject(weatherPlugin, "WeatherPlugin");
var kernel = builder.Build();
Use this when you need to control the plugin’s construction — passing specific dependencies, configuration, or a shared state object.
Option C: Import after building
var kernel = builder.Build();
kernel.ImportPluginFromType<WeatherPlugin>();
This works but means the plugin was not available during the builder phase. Prefer registration during builder setup for consistency.
Root Cause 4: Parameter Type Issues
When the AI model calls a function, it passes arguments as JSON. Semantic Kernel deserializes those into the method parameters. If the types are incompatible, invocation fails at runtime.
Common problems:
- Using
DateTimeinstead ofstringfor date parameters (the model outputs dates as strings) - Using custom types without a
JsonConverter - Using
enumtypes without[Description]to tell the model the valid values
Broken:
[KernelFunction]
public string GetWeatherForDate(string city, DateTime date) // DateTime parsing can fail
{
// ...
}
Fixed:
[KernelFunction("GetWeatherForDate")]
[Description("Gets the weather forecast for a city on a specific date")]
public string GetWeatherForDate(
[Description("City name")] string city,
[Description("Date in ISO 8601 format, e.g. '2026-03-01'")] string date)
{
var parsedDate = DateTime.Parse(date);
// ...
}
Accept strings for dates and do the parsing yourself. This is more robust against the variety of date formats that language models produce.
Root Cause 5: Missing [Description] Attributes
Missing [Description] attributes do not cause hard errors. The plugin registers fine, and manual invocation works. But during automatic function calling, the AI model has no idea what the function does or what each parameter means. The function is effectively invisible to the model’s decision-making process.
Not enough:
[KernelFunction]
public string SearchDatabase(string query, int maxResults) { ... }
Production-ready:
[KernelFunction("SearchDatabase")]
[Description("Searches the product database and returns matching items")]
public string SearchDatabase(
[Description("The search query, e.g. 'wireless headphones under $50'")] string query,
[Description("Maximum number of results to return, between 1 and 20")] int maxResults)
{
// ...
}
Detailed descriptions dramatically improve the model’s ability to select the right function and pass appropriate arguments.
Diagnostic: Inspecting Registered Plugins
When a function is not being found, verify what the kernel actually has registered:
var kernel = builder.Build();
foreach (var plugin in kernel.Plugins)
{
Console.WriteLine($"Plugin: {plugin.Name}");
foreach (var function in plugin)
{
Console.WriteLine($" Function: {function.Name}");
Console.WriteLine($" Description: {function.Description}");
foreach (var param in function.Metadata.Parameters)
{
Console.WriteLine($" Param: {param.Name} ({param.ParameterType?.Name}) " +
$"- {param.Description}");
}
}
}
Run this at startup. If a function you expect is missing from the output, go back and check the attribute and visibility. This diagnostic loop takes milliseconds and saves hours of guessing.
Complete Working Example
Here is a properly configured plugin with automatic function calling:
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.AzureOpenAI;
using System.ComponentModel;
// 1. Define the plugin with proper attributes
public class TimePlugin
{
[KernelFunction("GetCurrentTime")]
[Description("Gets the current date and time in the specified timezone")]
public string GetCurrentTime(
[Description("IANA timezone identifier, e.g. 'America/New_York'")] string timezone)
{
try
{
var tz = TimeZoneInfo.FindSystemTimeZoneById(timezone);
var time = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, tz);
return $"Current time in {timezone}: {time:yyyy-MM-dd HH:mm:ss}";
}
catch (TimeZoneNotFoundException)
{
return $"Unknown timezone: {timezone}. Use IANA format like 'America/New_York'.";
}
}
}
// 2. Register and use it
var builder = Kernel.CreateBuilder();
builder.AddAzureOpenAIChatCompletion(
deploymentName: config["AzureOpenAI:DeploymentName"]!,
endpoint: config["AzureOpenAI:Endpoint"]!,
apiKey: config["AzureOpenAI:ApiKey"]!);
builder.Plugins.AddFromType<TimePlugin>();
var kernel = builder.Build();
// 3. Enable automatic function calling
var settings = new AzureOpenAIPromptExecutionSettings
{
FunctionChoiceBehavior = FunctionChoiceBehavior.Auto()
};
var chatService = kernel.GetRequiredService<IChatCompletionService>();
var history = new ChatHistory();
history.AddUserMessage("What time is it in Tokyo?");
var response = await chatService.GetChatMessageContentAsync(history, settings, kernel);
Console.WriteLine(response.Content);
Prevention Best Practices
- Add the diagnostic loop to your startup. Log all registered plugins and functions. This catches registration issues before any user request hits the system.
- Write unit tests for plugin registration. Create a test that builds the kernel, registers plugins, and asserts specific functions exist.
- Use descriptive names. The function name parameter in
[KernelFunction("Name")]becomes the identifier the AI model sees. Make it clear and unambiguous. - Keep parameter types simple. Strings, numbers, and booleans work reliably. For complex inputs, accept a JSON string parameter and deserialize it yourself.
- Handle exceptions inside plugin methods. A thrown exception during function invocation can crash the function-calling loop. Return error messages as strings instead.
Further Reading
- Semantic Kernel: Plugins Concepts
- Microsoft.SemanticKernel on NuGet
- Semantic Kernel Plugin Issues on GitHub