Error Handling
How to handle errors and exceptions when using the Planning Center API client library.
Exception Types
JsonApiException
The library throws JsonApiException for API-level errors. JsonApiException extends HttpRequestException and exposes the parsed JSON:API error details:
using Crews.PlanningCenter.Api.Models;
using System.Net;
try
{
var response = await org.People.WithId("123").GetAsync();
}
catch (JsonApiException ex)
{
Console.WriteLine($"API Error: {ex.Message}");
Console.WriteLine($"Status Code: {ex.StatusCode}");
// Inspect individual JSON:API errors from the response body
foreach (var error in ex.Errors)
{
Console.WriteLine($" [{error.Status}] {error.Title}: {error.Detail}");
}
}
Tip
Inspect JsonApiException.Errors - this collection contains structured error information from the API response body.
HttpRequestException
JsonApiException is a subclass of HttpRequestException, so you can catch it as HttpRequestException for network and HTTP-level errors. Catch JsonApiException first if you need access to the parsed Errors collection:
catch (JsonApiException ex)
{
// API returned a non-2xx status with a JSON:API error body
}
catch (HttpRequestException ex)
{
// Network failure or other HTTP error without a JSON:API body
Console.WriteLine($"Network Error: {ex.Message}");
}
Common Error Scenarios
Authentication Errors (401)
catch (JsonApiException ex) when (ex.StatusCode == HttpStatusCode.Unauthorized)
{
// Invalid or expired credentials
}
Authorization Errors (403)
catch (JsonApiException ex) when (ex.StatusCode == HttpStatusCode.Forbidden)
{
// Insufficient permissions — request appropriate scopes
}
Not Found Errors (404)
catch (JsonApiException ex) when (ex.StatusCode == HttpStatusCode.NotFound)
{
// Resource does not exist
}
Rate Limiting (429)
catch (JsonApiException ex) when (ex.StatusCode == HttpStatusCode.TooManyRequests)
{
// Rate limit exceeded — implement exponential backoff and retry
}
Resilience Patterns
Using Built-in Resilience Handler (.NET 8+)
When registering your HttpClient in ASP.NET Core, add the standard resilience handler for automatic retry and circuit-breaker behavior:
builder.Services.AddHttpClient("PlanningCenterApi", client =>
{
client.BaseAddress = new Uri(PlanningCenterAuthenticationDefaults.BaseUrl);
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = token;
})
.AddStandardResilienceHandler();