github/copilot-sdk · error · InvalidOperationException

No ToolInvocation was provided for the tool call.

Error message

No ToolInvocation was provided for the tool call.

What it means

When defining a tool, the library builds a parameter binder that extracts the ToolInvocation for each argument. If a required (non-defaulted) parameter receives no ToolInvocation at invocation time, this InvalidOperationException is thrown because the tool cannot be executed without it.

Solutions

  1. Ensure every tool call passes a ToolInvocation and all required (non-optional) parameter values
  2. Give the parameter a default value if it is genuinely optional
  3. Update callers when the tool signature gains new required parameters
  4. Validate the incoming tool-call payload before binding

Example fix

// before
// required parameter 'invocation' has no default; caller omitted it
var result = await tool.InvokeAsync(args);
// after
public async Task<object?> InvokeAsync(ToolInvocation invocation, Dictionary<string, object?> args)
{
    if (invocation is null) throw new ArgumentNullException(nameof(invocation));
    return await tool.InvokeAsync(invocation, args);
}
Defensive patterns

Strategy: validation

Validate before calling

if (invocation is null) throw new ArgumentNullException(nameof(invocation), "ToolInvocation is required for the tool call");

Type guard

bool InvocationProvided(ToolInvocation? invocation) => invocation is not null;

Try / catch

try { var result = await tool.InvokeAsync(invocation, args); }
catch (InvalidOperationException ex) when (ex.Message.Contains("ToolInvocation")) { /* reject the malformed tool call */ }

Prevention

When it happens

Trigger: Invoking a tool whose invocation context omitted the ToolInvocation for a required parameter — e.g. the caller passed null/absent invocation data, or the tool was invoked outside the normal Copilot tool-call flow.

Common situations: Manually invoking the bound delegate without supplying an invocation; a runtime sends a malformed tool call missing arguments; parameter lists changed (new required parameter added) while callers still use the old signature.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09). Data as JSON: /api/errors/43ea1827be338910. Report an issue: GitHub.

Appendix: source

Thrown at dotnet/src/CopilotTool.cs:86

                    return new AIFunctionFactoryOptions.ParameterBindingOptions
                    {
                        ExcludeFromSchema = true,
                        BindParameter = static (pi, arguments) =>
                        {
                            // CopilotClient/CopilotSession attach this context object before invoking the AIFunction.
                            if (arguments.Context is not null &&
                                arguments.Context.TryGetValue(typeof(ToolInvocation), out var invocation) &&
                                invocation is ToolInvocation toolInvocation)
                            {
                                return toolInvocation;
                            }

                            if (pi.HasDefaultValue)
                            {
                                return null;
                            }

                            throw new InvalidOperationException($"No {nameof(ToolInvocation)} was provided for the tool call.");
                        }
                    };
                }

                return bindingOptions;
            };
        }

        static void ApplyToolOptions(AIFunctionFactoryOptions factoryOptions, CopilotToolOptions? toolOptions)
        {
            if (toolOptions is not null && (toolOptions.OverridesBuiltInTool || toolOptions.SkipPermission || toolOptions.IsTerminal || toolOptions.Defer is not null || toolOptions.Metadata is not null))
            {
                Dictionary<string, object?> additionalProperties = new(StringComparer.Ordinal);
                if (factoryOptions.AdditionalProperties is not null)
                {
                    foreach (var (key, value) in factoryOptions.AdditionalProperties)
                    {
                        additionalProperties[key] = value;

View on GitHub (pinned to cd8cf15dc3)