microsoft/semantic-kernel · warning · InvalidOperationException

A helper with the name '{helperName}' is already registered.

Error message

A helper with the name '{helperName}' is already registered.

What it means

Thrown when attempting to register a Handlebars helper whose name already exists in the Handlebars configuration's Helpers dictionary. RegisterHelperSafe guards against silent overwrites of existing helpers.

Source

Thrown at dotnet/src/Extensions/PromptTemplates.Handlebars/Helpers/KernelHelperUtils.cs:26

namespace Microsoft.SemanticKernel.PromptTemplates.Handlebars.Helpers;

/// <summary>
/// Extension class to register additional helpers as Kernel System helpers.
/// </summary>
internal static class KernelHelpersUtils
{
    /// <summary>
    /// Registers a helper with the Handlebars instance, throwing an exception if a helper with the same name is already registered.
    /// </summary>
    /// <param name="handlebarsInstance">The <see cref="IHandlebars"/>-instance.</param>
    /// <param name="helperName">The name of the helper.</param>
    /// <param name="helper">The helper to register.</param>
    internal static void RegisterHelperSafe(IHandlebars handlebarsInstance, string helperName, HandlebarsReturnHelper helper)
    {
        if (handlebarsInstance.Configuration.Helpers.ContainsKey(helperName))
        {
            throw new InvalidOperationException($"A helper with the name '{helperName}' is already registered.");
        }

        handlebarsInstance.RegisterHelper(helperName, helper);
    }

    /// <summary>
    /// Returns value if defined, else, tries to resolve value from given KernelArguments dictionary.
    /// </summary>
    /// <param name="argument">Argument to process.</param>
    /// <param name="kernelArguments">Dictionary of variables maintained by the Handlebars context.</param>
    internal static object? GetArgumentValue(object argument, KernelArguments kernelArguments)
    {
        // If the argument is of type UndefinedBindingResult, it means that Handlebars attempted to retrieve the value for a binding 
        // but was unable to do so because the variable was not defined or not passed to the template context at the time of render.
        // Thus, we try to get the value from the kernel arguments dictionary.
        if (argument is UndefinedBindingResult result)
        {
            return kernelArguments.TryGetValue(result.Value, out var variable) ? variable : null;

View on GitHub (pinned to c028a0c7dc)

Solutions

  1. Choose a unique helper name (prefix with your plugin/namespace) to avoid collisions.
  2. Before registering, check handlebarsInstance.Configuration.Helpers.ContainsKey(name) and skip or replace deliberately.
  3. Initialize helpers only once per Handlebars instance lifetime.

Example fix

// before
KernelHelpersUtils.RegisterHelperSafe(handlebars, "message", helper);
KernelHelpersUtils.RegisterHelperSafe(handlebars, "message", other); // throws
// after
if (!handlebars.Configuration.Helpers.ContainsKey("myPlugin_message"))
{
    KernelHelpersUtils.RegisterHelperSafe(handlebars, "myPlugin_message", helper);
}
Defensive patterns

Strategy: validation

Validate before calling

if (handlebars.Configuration.Helpers.ContainsKey(helperName))
    throw new InvalidOperationException($"Helper '{helperName}' already registered; choose a unique name.");
KernelHelpersUtils.RegisterHelperSafe(handlebars, helperName, helper);

Type guard

public static bool IsHelperRegistered(IHandlebars handlebars, string name) =>
    handlebars.Configuration.Helpers.ContainsKey(name);

Try / catch

try
{
    KernelHelpersUtils.RegisterHelperSafe(handlebars, name, helper);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("already registered"))
{
    _logger.LogWarning("Helper '{Name}' already registered; skipping.", name);
}

Prevention

When it happens

Trigger: KernelHelpersUtils.RegisterHelperSafe is called with a helperName that already has an entry in handlebarsInstance.Configuration.Helpers, e.g., registering the same helper twice or using a name that collides with a built-in.

Common situations: Registering a custom helper with a name that clashes with a system helper (e.g., 'message'), re-registering helpers across multiple initialization calls without checking existence, or plugin name collisions.

Related errors


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