> For the complete documentation index, see [llms.txt](https://docs.partssource.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.partssource.com/api/core-concepts/error-handling.md).

# Error Handling

Understanding and handling API error responses

The PartsSource APIs use standard HTTP status codes and return detailed error information following [RFC 7807](https://tools.ietf.org/html/rfc7807) (Problem Details for HTTP APIs).

***

## HTTP Status Codes

### Success Codes (2xx)

| Code             | Meaning              | Usage                                  |
| ---------------- | -------------------- | -------------------------------------- |
| `200 OK`         | Request succeeded    | GET, POST search, successful mutations |
| `201 Created`    | Resource created     | POST that creates resources            |
| `204 No Content` | Success with no body | DELETE operations                      |

### Client Error Codes (4xx)

| Code                    | Meaning                 | Common Causes                            |
| ----------------------- | ----------------------- | ---------------------------------------- |
| `400 Bad Request`       | Invalid request         | Validation errors, malformed JSON        |
| `401 Unauthorized`      | Authentication required | Missing/invalid/expired token            |
| `403 Forbidden`         | Access denied           | Valid token but insufficient permissions |
| `404 Not Found`         | Resource not found      | Invalid ID, resource doesn't exist       |
| `409 Conflict`          | State conflict          | Idempotency conflict, concurrent update  |
| `422 Unprocessable`     | Semantic error          | Valid format but business rule violation |
| `429 Too Many Requests` | Rate limited            | Exceeded request quota                   |

### Server Error Codes (5xx)

| Code                        | Meaning          | Common Causes                |
| --------------------------- | ---------------- | ---------------------------- |
| `500 Internal Server Error` | Unexpected error | Bug, unhandled exception     |
| `502 Bad Gateway`           | Upstream failure | External service unavailable |
| `503 Service Unavailable`   | Temporary outage | Maintenance, overload        |
| `504 Gateway Timeout`       | Upstream timeout | External service slow        |

***

## Error Response Formats

The API returns errors in different formats depending on where the error occurs.

### Standard Error Response

For errors handled at the controller level:

```json
{
  "success": false,
  "errors": [
    "Customer not found",
    "Additional error message if applicable"
  ],
  "correlationId": "0HN7QJKV3QJ8K:00000001",
  "timestamp": "2025-10-21T14:30:00.000Z"
}
```

| Field           | Type      | Description                             |
| --------------- | --------- | --------------------------------------- |
| `success`       | boolean   | Always `false` for errors               |
| `errors`        | string\[] | Array of error messages                 |
| `correlationId` | string    | Unique request identifier for debugging |
| `timestamp`     | string    | ISO 8601 timestamp                      |

### Problem Details Response (RFC 7807)

For errors handled at the exception/middleware level:

```json
{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.4",
  "title": "Resource Not Found",
  "status": 404,
  "detail": "Customer with ID '12345' was not found.",
  "correlationId": "0HN7QJKV3QJ8K:00000001",
  "timestamp": "2025-10-21T14:30:00.000Z",
  "service": "CustomerApi"
}
```

| Field           | Type    | Description                              |
| --------------- | ------- | ---------------------------------------- |
| `type`          | string  | URI reference identifying the error type |
| `title`         | string  | Short, human-readable summary            |
| `status`        | integer | HTTP status code                         |
| `detail`        | string  | Human-readable explanation               |
| `correlationId` | string  | Unique request identifier                |
| `timestamp`     | string  | ISO 8601 timestamp                       |
| `service`       | string  | Which API returned the error             |

### Validation Error Response

For request validation failures (400 Bad Request):

```json
{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "Validation Failed",
  "status": 400,
  "detail": "One or more validation errors occurred.",
  "correlationId": "0HN7QJKV3QJ8K:00000001",
  "errors": {
    "email": ["Email address is required"],
    "firstName": ["First name must not exceed 50 characters"],
    "quoteItems": ["At least one item is required"]
  }
}
```

The `errors` object contains field-level validation messages:

* Keys are field names (using camelCase)
* Values are arrays of error messages for that field

***

## Common Error Scenarios

### Authentication Errors (401)

```json
{
  "type": "https://tools.ietf.org/html/rfc7235#section-3.1",
  "title": "Unauthorized",
  "status": 401,
  "detail": "Authentication is required to access this resource.",
  "correlationId": "0HN7QJKV3QJ8K:00000001"
}
```

**Causes:**

* Missing `Authorization` header
* Invalid or malformed token
* Expired token (tokens expire after 1 hour)
* Token signature validation failed

**Solution:** Obtain a new access token and retry.

### Forbidden Errors (403)

```json
{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.3",
  "title": "Forbidden",
  "status": 403,
  "detail": "You do not have permission to access this resource.",
  "correlationId": "0HN7QJKV3QJ8K:00000001"
}
```

**Causes:**

* Attempting to access another tenant's data (CustomerApi)
* User doesn't have access to the requested facility

**Solution:** Verify your client credentials have the required permissions.

### Not Found Errors (404)

```json
{
  "success": false,
  "errors": ["Customer not found"],
  "correlationId": "0HN7QJKV3QJ8K:00000001",
  "timestamp": "2025-10-21T14:30:00.000Z"
}
```

**Causes:**

* Resource ID doesn't exist
* Resource was deleted
* Typo in the resource identifier

### Idempotency Conflict (409)

```json
{
  "error": "Request body does not match the original request for this idempotency key."
}
```

**Causes:**

* Reusing an idempotency key with different request body
* Request is still processing from a previous attempt

**Solution:** Wait and retry, or use a new idempotency key for a different operation.

***

## Error Handling Best Practices

### 1. Always Check the `success` Field

```csharp
var response = await httpClient.PostAsync("/api/orders", content);
var result = await response.Content.ReadFromJsonAsync<ApiResponse<Order>>();

if (!result.Success)
{
    foreach (var error in result.Errors)
    {
        Console.WriteLine($"Error: {error}");
    }
    return;
}

// Process result.Data
```

### 2. Log the Correlation ID

Always log the `correlationId` for debugging with support:

```csharp
if (!response.IsSuccessStatusCode)
{
    var error = await response.Content.ReadFromJsonAsync<ProblemDetails>();
    _logger.LogError(
        "API error: {Title}. CorrelationId: {CorrelationId}",
        error.Title,
        error.CorrelationId);
}
```

### 3. Handle Validation Errors Gracefully

Parse field-level errors for user-friendly messages:

```csharp
if (response.StatusCode == HttpStatusCode.BadRequest)
{
    var validation = await response.Content.ReadFromJsonAsync<ValidationProblemDetails>();

    foreach (var (field, messages) in validation.Errors)
    {
        foreach (var message in messages)
        {
            Console.WriteLine($"{field}: {message}");
        }
    }
}
```

### 4. Implement Retry Logic for 5xx Errors

Use exponential backoff for server errors:

```csharp
public async Task<T> ExecuteWithRetry<T>(Func<Task<HttpResponseMessage>> action, int maxRetries = 3)
{
    for (int attempt = 1; attempt <= maxRetries; attempt++)
    {
        var response = await action();

        if (response.IsSuccessStatusCode)
        {
            return await response.Content.ReadFromJsonAsync<T>();
        }

        // Don't retry client errors (4xx) - they won't succeed without changes
        if ((int)response.StatusCode >= 400 && (int)response.StatusCode < 500)
        {
            throw new ApiException(await response.Content.ReadAsStringAsync());
        }

        // Retry server errors (5xx) with exponential backoff
        if (attempt < maxRetries)
        {
            var delay = TimeSpan.FromSeconds(Math.Pow(2, attempt));
            await Task.Delay(delay);
        }
    }

    throw new MaxRetriesExceededException();
}
```

### 5. Don't Retry 4xx Errors Without Changes

Client errors (4xx) indicate a problem with your request. Retrying without modification won't help.

| Error | Action                                          |
| ----- | ----------------------------------------------- |
| `400` | Fix validation errors, then retry               |
| `401` | Get new token, then retry                       |
| `403` | Check permissions - may not be retryable        |
| `404` | Verify resource exists                          |
| `409` | Wait (if processing) or use new idempotency key |
| `429` | Wait for rate limit reset                       |

***

## Code Examples

### TypeScript

```typescript
interface ApiError {
  success: false;
  errors: string[];
  correlationId: string;
  timestamp: string;
}

interface ValidationError {
  type: string;
  title: string;
  status: number;
  detail: string;
  errors: Record<string, string[]>;
  correlationId: string;
}

async function handleApiResponse<T>(response: Response): Promise<T> {
  if (response.ok) {
    const data = await response.json();
    return data.data as T;
  }

  if (response.status === 400) {
    const validation: ValidationError = await response.json();
    console.error('Validation errors:', validation.errors);
    throw new ValidationException(validation);
  }

  const error: ApiError = await response.json();
  console.error(`API Error [${error.correlationId}]:`, error.errors);
  throw new ApiException(error);
}
```

### Python

```python
import requests
from typing import TypeVar, Generic

T = TypeVar('T')

def handle_response(response: requests.Response) -> dict:
    if response.ok:
        data = response.json()
        return data.get('data')

    error = response.json()
    correlation_id = error.get('correlationId', 'unknown')

    if response.status_code == 400:
        # Validation error
        errors = error.get('errors', {})
        for field, messages in errors.items():
            for msg in messages:
                print(f"Validation error - {field}: {msg}")
        raise ValidationError(errors, correlation_id)

    if response.status_code == 401:
        raise AuthenticationError("Token expired or invalid", correlation_id)

    if response.status_code >= 500:
        raise ServerError(f"Server error: {error.get('title')}", correlation_id)

    raise ApiError(error.get('errors', ['Unknown error']), correlation_id)
```

***

## Troubleshooting

### "Authentication is required"

1. Verify your `Authorization` header is present
2. Check token format: `Bearer <token>` (with space after "Bearer")
3. Verify token hasn't expired (1 hour lifetime)
4. Request a new token if expired

### "Validation Failed" with empty errors

1. Check `Content-Type` header is `application/json`
2. Verify JSON body is properly formatted
3. Check for encoding issues in the request body

### Receiving HTML instead of JSON

1. Verify the URL path is correct
2. Check you're using HTTPS (not HTTP)
3. Verify the base URL is correct for your environment

### Getting 5xx errors consistently

1. Note the `correlationId` from the response
2. Contact support with the correlation ID
3. Check the [health endpoints](https://github.com/PartsSourceInc/gitbook-documentation/blob/main/documentation/api-reference/health.md) for service status


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.partssource.com/api/core-concepts/error-handling.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
