microsoft/semantic-kernel · critical · InvalidOperationException

Please provide a valid OpenAI:ApiKey to run this sample. See

Error message

Please provide a valid OpenAI:ApiKey to run this sample. See the associated README.md for more details.

What it means

BaseSample.CreateKernelWithChatCompletionService builds config from user secrets + env vars and throws InvalidOperationException if OpenAI:ApiKey is absent. ChatModelId defaults to gpt-4o-mini if unset, but the API key is mandatory and has no default. The message is written to stderr before throwing.

Source

Thrown at dotnet/samples/Demos/ModelContextProtocolClientServer/MCPClient/Samples/BaseSample.cs:90

    }

    /// <summary>
    /// Creates an instance of <see cref="Kernel"/> with the OpenAI chat completion service registered.
    /// </summary>
    /// <returns>An instance of <see cref="Kernel"/>.</returns>
    protected static Kernel CreateKernelWithChatCompletionService()
    {
        // Load and validate configuration
        IConfigurationRoot config = new ConfigurationBuilder()
            .AddUserSecrets<Program>()
            .AddEnvironmentVariables()
            .Build();

        if (config["OpenAI:ApiKey"] is not { } apiKey)
        {
            const string Message = "Please provide a valid OpenAI:ApiKey to run this sample. See the associated README.md for more details.";
            Console.Error.WriteLine(Message);
            throw new InvalidOperationException(Message);
        }

        string modelId = config["OpenAI:ChatModelId"] ?? "gpt-4o-mini";

        // Create kernel
        var kernelBuilder = Kernel.CreateBuilder();
        kernelBuilder.Services.AddOpenAIChatCompletion(modelId: modelId, apiKey: apiKey);

        return kernelBuilder.Build();
    }

    /// <summary>
    /// Displays the list of available MCP tools.
    /// </summary>
    /// <param name="tools">The list of the tools to display.</param>
    protected static void DisplayTools(IList<McpClientTool> tools)
    {
        Console.WriteLine("Available MCP tools:");

View on GitHub (pinned to c028a0c7dc)

Solutions

  1. dotnet user-secrets set OpenAI:ApiKey <your-key>.
  2. Or export OPENAI__ApiKey environment variable (use the __ hierarchy separator).
  3. Optionally set OpenAI:ChatModelId if you don't want the gpt-4o-mini default.
  4. Verify the user-secrets ID matches this project so secrets resolve.

Example fix

// before
if (config["OpenAI:ApiKey"] is not { } apiKey)
{
    const string Message = "Please provide a valid OpenAI:ApiKey to run this sample...";
    Console.Error.WriteLine(Message);
    throw new InvalidOperationException(Message);
}

// after (user secret)
// dotnet user-secrets set OpenAI:ApiKey sk-...
// dotnet user-secrets set OpenAI:ChatModelId gpt-4o
Defensive patterns

Strategy: validation

Validate before calling

if (config["OpenAI:ApiKey"] is not { } apiKey)
    throw new InvalidOperationException(
        "Set OpenAI:ApiKey via user secrets or OPENAI__ApiKey env var.");

Type guard

static bool HasOpenAiKey(IConfigurationRoot c) =>
    !string.IsNullOrEmpty(c["OpenAI:ApiKey"]);

Prevention

When it happens

Trigger: config["OpenAI:ApiKey"] is null after merging user secrets and environment variables.

Common situations: First run without user secrets, OPENAI_API_KEY env var not exported, or user-secrets ID bound to a different project.

Related errors


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