Files
awesome-copilot/cookbook/copilot-sdk/dotnet/error-handling.md
2026-01-29 14:29:36 +11:00

3.4 KiB

Error Handling Patterns

Handle errors gracefully in your Copilot SDK applications.

Runnable example: recipe/error-handling.cs

dotnet run recipe/error-handling.cs

Example scenario

You need to handle various error conditions like connection failures, timeouts, and invalid responses.

Basic try-catch

using GitHub.Copilot.SDK;

var client = new CopilotClient();

try
{
    await client.StartAsync();
    var session = await client.CreateSessionAsync(new SessionConfig
    {
        Model = "gpt-5"
    });

    var done = new TaskCompletionSource<string>();
    session.On(evt =>
    {
        if (evt is AssistantMessageEvent msg)
        {
            done.SetResult(msg.Data.Content);
        }
    });

    await session.SendAsync(new MessageOptions { Prompt = "Hello!" });
    var response = await done.Task;
    Console.WriteLine(response);

    await session.DisposeAsync();
}
catch (Exception ex)
{
    Console.WriteLine($"Error: {ex.Message}");
}
finally
{
    await client.StopAsync();
}

Handling specific error types

try
{
    await client.StartAsync();
}
catch (FileNotFoundException)
{
    Console.WriteLine("Copilot CLI not found. Please install it first.");
}
catch (HttpRequestException ex) when (ex.Message.Contains("connection"))
{
    Console.WriteLine("Could not connect to Copilot CLI server.");
}
catch (Exception ex)
{
    Console.WriteLine($"Unexpected error: {ex.Message}");
}

Timeout handling

var session = await client.CreateSessionAsync(new SessionConfig { Model = "gpt-5" });

try
{
    var done = new TaskCompletionSource<string>();
    session.On(evt =>
    {
        if (evt is AssistantMessageEvent msg)
        {
            done.SetResult(msg.Data.Content);
        }
    });

    await session.SendAsync(new MessageOptions { Prompt = "Complex question..." });

    // Wait with timeout (30 seconds)
    using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
    var response = await done.Task.WaitAsync(cts.Token);

    Console.WriteLine(response);
}
catch (OperationCanceledException)
{
    Console.WriteLine("Request timed out");
}

Aborting a request

var session = await client.CreateSessionAsync(new SessionConfig { Model = "gpt-5" });

// Start a request
await session.SendAsync(new MessageOptions { Prompt = "Write a very long story..." });

// Abort it after some condition
await Task.Delay(5000);
await session.AbortAsync();
Console.WriteLine("Request aborted");

Graceful shutdown

Console.CancelKeyPress += async (sender, e) =>
{
    e.Cancel = true;
    Console.WriteLine("Shutting down...");

    var errors = await client.StopAsync();
    if (errors.Count > 0)
    {
        Console.WriteLine($"Cleanup errors: {string.Join(", ", errors)}");
    }

    Environment.Exit(0);
};

Using await using for automatic disposal

await using var client = new CopilotClient();
await client.StartAsync();

var session = await client.CreateSessionAsync(new SessionConfig { Model = "gpt-5" });

// ... do work ...

// client.StopAsync() is automatically called when exiting scope

Best practices

  1. Always clean up: Use try-finally or await using to ensure StopAsync() is called
  2. Handle connection errors: The CLI might not be installed or running
  3. Set appropriate timeouts: Use CancellationToken for long-running requests
  4. Log errors: Capture error details for debugging