> ## Documentation Index
> Fetch the complete documentation index at: https://team.k0labs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors

> Error handling, status codes, and error response structures

> Common error codes and their meanings

The k0rdent API uses standard HTTP status codes and structured error responses to communicate failures clearly.

## Error Response Structure

All error responses follow a consistent structure with the discriminated union envelope:

```json theme={null}
{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid request body",
    "details": {
      "fields": {
        "name": "Name is required",
        "bmcAddress": "Invalid BMC address format"
      }
    }
  },
  "meta": {
    "requestId": "req_sfo1-1770564159296-7d4b9e1f3a5b",
    "timestamp": "2025-01-09T12:00:00.000Z"
  }
}
```

### Error Object Fields

| Field     | Type   | Description                      |
| --------- | ------ | -------------------------------- |
| `code`    | string | Machine-readable error code      |
| `message` | string | Human-readable error description |
| `details` | object | Additional context (optional)    |

## HTTP Status Codes

The k0rdent API uses the following HTTP status codes:

| Code  | Usage                                 |
| ----- | ------------------------------------- |
| `200` | Success (GET, PATCH, DELETE)          |
| `201` | Created (POST that creates resource)  |
| `202` | Accepted (async operation started)    |
| `204` | No Content (DELETE with no body)      |
| `207` | Multi-Status (bulk operations)        |
| `400` | Bad Request (validation error)        |
| `401` | Unauthorized (no/invalid auth)        |
| `403` | Forbidden (valid auth, no permission) |
| `404` | Not Found                             |
| `409` | Conflict (resource state conflict)    |
| `422` | Unprocessable Entity (semantic error) |
| `429` | Too Many Requests (rate limited)      |
| `500` | Internal Server Error                 |

### Key Patterns

* Use `202 Accepted` for all async operations (BMC, K8s interactions)
* Use `207 Multi-Status` for all batch operations (indicates partial success possible)
* Use `409 Conflict` for invalid state transitions (e.g., provisioning an already-provisioned server)
* Always include error codes in response body, not just HTTP status

## Common Error Codes

The API uses machine-readable error codes in the `error.code` field:

| Code                       | HTTP Status | Description                                |
| -------------------------- | ----------- | ------------------------------------------ |
| `VALIDATION_ERROR`         | 400         | Request validation failed                  |
| `NOT_FOUND`                | 404         | Resource not found                         |
| `FORBIDDEN`                | 403         | Insufficient permissions                   |
| `UNAUTHORIZED`             | 401         | Invalid or missing authentication          |
| `CONFLICT`                 | 409         | Resource state conflict                    |
| `INVALID_STATE_TRANSITION` | 409         | Cannot transition resource to target state |
| `POOL_CAPACITY_EXCEEDED`   | 409         | Not enough resources in pool               |
| `QUOTA_EXCEEDED`           | 403         | Organization quota exceeded                |
| `BMC_CONNECTION_FAILED`    | 500         | Cannot connect to BMC                      |
| `INTERNAL_ERROR`           | 500         | Unexpected server error                    |

## Error Examples

### Validation Error

```json theme={null}
{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid request body",
    "details": {
      "fields": {
        "name": "Name is required",
        "region": "Invalid region code"
      }
    }
  },
  "meta": {
    "requestId": "req_sfo1-1770564159296-7d4b9e1f3a5b",
    "timestamp": "2025-01-09T12:00:00.000Z"
  }
}
```

### Not Found Error

```json theme={null}
{
  "success": false,
  "error": {
    "code": "NOT_FOUND",
    "message": "Server not found: srv_abc123"
  },
  "meta": {
    "requestId": "req_sfo1-1770564159296-7d4b9e1f3a5b",
    "timestamp": "2025-01-09T12:00:00.000Z"
  }
}
```

### Invalid State Transition

```json theme={null}
{
  "success": false,
  "error": {
    "code": "INVALID_STATE_TRANSITION",
    "message": "Cannot provision server in 'allocated' state",
    "details": {
      "currentState": "allocated",
      "requiredState": "available"
    }
  },
  "meta": {
    "requestId": "req_sfo1-1770564159296-7d4b9e1f3a5b",
    "timestamp": "2025-01-09T12:00:00.000Z"
  }
}
```

### Capacity Exceeded

```json theme={null}
{
  "success": false,
  "error": {
    "code": "POOL_CAPACITY_EXCEEDED",
    "message": "Not enough available servers in pool gpu-h100-pool",
    "details": {
      "poolId": "pool_abc123",
      "requested": 10,
      "available": 3
    }
  },
  "meta": {
    "requestId": "req_sfo1-1770564159296-7d4b9e1f3a5b",
    "timestamp": "2025-01-09T12:00:00.000Z"
  }
}
```

## Typed Error Classes

The k0rdent API implementation uses typed error classes for consistency:

### AppError

Base error class for all application errors:

```typescript theme={null}
class AppError extends Error {
  constructor(
    public code: string,
    message: string,
    public statusCode: number = 500,
    public details?: unknown
  )
}
```

### ValidationError

Used for request validation failures:

```typescript theme={null}
class ValidationError extends AppError {
  constructor(message: string, details?: unknown) {
    super('VALIDATION_ERROR', message, 400, details)
  }
}
```

### NotFoundError

Used when a resource cannot be found:

```typescript theme={null}
class NotFoundError extends AppError {
  constructor(resource: string, id: string) {
    super('NOT_FOUND', `${resource} not found: ${id}`, 404)
  }
}
```

### ForbiddenError

Used when the user lacks permission:

```typescript theme={null}
class ForbiddenError extends AppError {
  constructor(message: string = 'Access denied') {
    super('FORBIDDEN', message, 403)
  }
}
```

### ConflictError

Used for resource state conflicts:

```typescript theme={null}
class ConflictError extends AppError {
  constructor(message: string) {
    super('CONFLICT', message, 409)
  }
}
```

### InvalidStateTransitionError

Used for invalid state transitions:

```typescript theme={null}
class InvalidStateTransitionError extends ConflictError {
  constructor(resource: string, currentState: string, targetState: string) {
    super(
      `Cannot transition ${resource} from ${currentState} to ${targetState}`
    )
    this.code = 'INVALID_STATE_TRANSITION'
  }
}
```

## Bulk Operation Errors

Bulk operations use `207 Multi-Status` with per-resource error details:

```json theme={null}
{
  "success": true,
  "data": {
    "action": "power",
    "requested": 3,
    "succeeded": 2,
    "failed": 1,
    "results": [
      {
        "id": "srv_123",
        "status": "success"
      },
      {
        "id": "srv_456",
        "status": "success"
      },
      {
        "id": "srv_789",
        "status": "failed",
        "error": {
          "code": "BMC_CONNECTION_FAILED",
          "message": "Cannot connect to BMC"
        }
      }
    ]
  },
  "meta": {
    "requestId": "req_sfo1-1770564159296-7d4b9e1f3a5b",
    "timestamp": "2025-01-09T12:00:00.000Z"
  }
}
```

Note: Bulk operations always return `success: true` at the top level, with per-resource status in the results array.

## Error Handling Best Practices

### For API Consumers

* **Check the `success` field** - Use TypeScript discriminated unions for type safety
* **Log `requestId`** - Always log the request ID for debugging
* **Handle specific error codes** - Don't rely solely on HTTP status codes
* **Parse `details` field** - Provides additional context for validation errors
* **Implement retries** - For `500` and `429` errors with exponential backoff

### Example Client Code

```typescript theme={null}
const response = await fetch('/v1/region/sfo1/compute/clusters', {
  method: 'POST',
  body: JSON.stringify(data)
})

const json = await response.json()

if (!json.success) {
  console.error('Request failed:', {
    requestId: json.meta.requestId,
    code: json.error.code,
    message: json.error.message
  })
  
  // Handle specific errors
  switch (json.error.code) {
    case 'VALIDATION_ERROR':
      // Show validation errors to user
      break
    case 'POOL_CAPACITY_EXCEEDED':
      // Suggest different pool or region
      break
    default:
      // Generic error handling
  }
}
```

## Rate Limiting

Rate limit errors return `429 Too Many Requests` with a `Retry-After` header indicating when to retry.

```json theme={null}
{
  "success": false,
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Too many requests. Please retry after 60 seconds."
  },
  "meta": {
    "requestId": "req_sfo1-1770564159296-7d4b9e1f3a5b",
    "timestamp": "2025-01-09T12:00:00.000Z"
  }
}
```

Check the `Retry-After` response header for the recommended retry delay in seconds.
