Skip to main content
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:
{
  "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

FieldTypeDescription
codestringMachine-readable error code
messagestringHuman-readable error description
detailsobjectAdditional context (optional)

HTTP Status Codes

The k0rdent API uses the following HTTP status codes:
CodeUsage
200Success (GET, PATCH, DELETE)
201Created (POST that creates resource)
202Accepted (async operation started)
204No Content (DELETE with no body)
207Multi-Status (bulk operations)
400Bad Request (validation error)
401Unauthorized (no/invalid auth)
403Forbidden (valid auth, no permission)
404Not Found
409Conflict (resource state conflict)
422Unprocessable Entity (semantic error)
429Too Many Requests (rate limited)
500Internal 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:
CodeHTTP StatusDescription
VALIDATION_ERROR400Request validation failed
NOT_FOUND404Resource not found
FORBIDDEN403Insufficient permissions
UNAUTHORIZED401Invalid or missing authentication
CONFLICT409Resource state conflict
INVALID_STATE_TRANSITION409Cannot transition resource to target state
POOL_CAPACITY_EXCEEDED409Not enough resources in pool
QUOTA_EXCEEDED403Organization quota exceeded
BMC_CONNECTION_FAILED500Cannot connect to BMC
INTERNAL_ERROR500Unexpected server error

Error Examples

Validation Error

{
  "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

{
  "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

{
  "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

{
  "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:
class AppError extends Error {
  constructor(
    public code: string,
    message: string,
    public statusCode: number = 500,
    public details?: unknown
  )
}

ValidationError

Used for request validation failures:
class ValidationError extends AppError {
  constructor(message: string, details?: unknown) {
    super('VALIDATION_ERROR', message, 400, details)
  }
}

NotFoundError

Used when a resource cannot be found:
class NotFoundError extends AppError {
  constructor(resource: string, id: string) {
    super('NOT_FOUND', `${resource} not found: ${id}`, 404)
  }
}

ForbiddenError

Used when the user lacks permission:
class ForbiddenError extends AppError {
  constructor(message: string = 'Access denied') {
    super('FORBIDDEN', message, 403)
  }
}

ConflictError

Used for resource state conflicts:
class ConflictError extends AppError {
  constructor(message: string) {
    super('CONFLICT', message, 409)
  }
}

InvalidStateTransitionError

Used for invalid state transitions:
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:
{
  "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

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.
{
  "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.