---
title: Error Handling
description: Understanding and handling API errors in TraceRTM including error codes, retry strategies, and troubleshooting
---

# Error Handling

This guide covers how TraceRTM API errors are structured, common error scenarios, and best practices for handling errors in your applications.

## Error Response Format

All API errors follow a consistent JSON structure:

```json
{
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable error description",
    "details": {
      "field": "specific_field",
      "reason": "Additional context"
    },
    "request_id": "req_abc123xyz",
    "documentation_url": "https://docs.tracertm.dev/errors/ERROR_CODE"
  }
}
```

### Error Fields

| Field | Type | Description |
|-------|------|-------------|
| `code` | string | Machine-readable error code |
| `message` | string | Human-readable description |
| `details` | object | Additional error context (optional) |
| `request_id` | string | Unique request identifier for support |
| `documentation_url` | string | Link to error documentation |

---

## HTTP Status Codes

### Success Codes

| Code | Meaning | Description |
|------|---------|-------------|
| `200` | OK | Request succeeded |
| `201` | Created | Resource created successfully |
| `202` | Accepted | Request accepted for async processing |
| `204` | No Content | Success with no response body |

### Client Error Codes (4xx)

| Code | Meaning | Description |
|------|---------|-------------|
| `400` | Bad Request | Invalid request syntax or parameters |
| `401` | Unauthorized | Missing or invalid authentication |
| `403` | Forbidden | Insufficient permissions |
| `404` | Not Found | Resource doesn't exist |
| `405` | Method Not Allowed | HTTP method not supported |
| `409` | Conflict | Resource conflict (e.g., duplicate) |
| `422` | Unprocessable Entity | Validation failed |
| `429` | Too Many Requests | Rate limit exceeded |

### Server Error Codes (5xx)

| Code | Meaning | Description |
|------|---------|-------------|
| `500` | Internal Server Error | Unexpected server error |
| `502` | Bad Gateway | Upstream service error |
| `503` | Service Unavailable | Service temporarily unavailable |
| `504` | Gateway Timeout | Request timeout |

---

## Common Errors

### Authentication Errors (401)

#### Missing API Key

```json
{
  "error": {
    "code": "AUTHENTICATION_REQUIRED",
    "message": "API key is required",
    "details": {
      "header": "Authorization",
      "expected_format": "Bearer rtm_live_sk_..."
    }
  }
}
```

#### Invalid API Key

```json
{
  "error": {
    "code": "INVALID_API_KEY",
    "message": "The provided API key is invalid",
    "details": {
      "key_prefix": "rtm_live_sk_abc",
      "reason": "key_not_found"
    }
  }
}
```

#### Expired API Key

```json
{
  "error": {
    "code": "API_KEY_EXPIRED",
    "message": "This API key has expired",
    "details": {
      "expired_at": "2024-01-15T00:00:00Z",
      "action": "Generate a new API key in your dashboard"
    }
  }
}
```

### Authorization Errors (403)

#### Insufficient Permissions

```json
{
  "error": {
    "code": "FORBIDDEN",
    "message": "You don't have permission to perform this action",
    "details": {
      "required_permission": "items:write",
      "user_permissions": ["items:read", "projects:read"],
      "resource": "item_req_001"
    }
  }
}
```

#### Project Access Denied

```json
{
  "error": {
    "code": "PROJECT_ACCESS_DENIED",
    "message": "You don't have access to this project",
    "details": {
      "project_id": "proj_abc123",
      "action": "Request access from the project owner"
    }
  }
}
```

### Not Found Errors (404)

#### Resource Not Found

```json
{
  "error": {
    "code": "NOT_FOUND",
    "message": "The requested resource was not found",
    "details": {
      "resource_type": "item",
      "resource_id": "item_req_999",
      "suggestion": "Verify the ID and ensure the resource exists"
    }
  }
}
```

#### Project Not Found

```json
{
  "error": {
    "code": "PROJECT_NOT_FOUND",
    "message": "Project not found",
    "details": {
      "project_id": "proj_invalid",
      "suggestion": "Check the project ID or list available projects"
    }
  }
}
```

### Validation Errors (422)

#### Field Validation

```json
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "details": {
      "errors": [
        {
          "field": "title",
          "code": "required",
          "message": "Title is required"
        },
        {
          "field": "priority",
          "code": "invalid_value",
          "message": "Priority must be one of: critical, high, medium, low, trivial",
          "received": "urgent"
        },
        {
          "field": "due_date",
          "code": "invalid_format",
          "message": "Due date must be in ISO 8601 format",
          "received": "January 20, 2024"
        }
      ]
    }
  }
}
```

#### Workflow Validation

```json
{
  "error": {
    "code": "INVALID_STATUS_TRANSITION",
    "message": "Invalid status transition",
    "details": {
      "current_status": "draft",
      "requested_status": "approved",
      "allowed_transitions": ["in_review", "rejected"],
      "workflow": "requirement_workflow"
    }
  }
}
```

### Conflict Errors (409)

#### Duplicate Resource

```json
{
  "error": {
    "code": "DUPLICATE_RESOURCE",
    "message": "A resource with this key already exists",
    "details": {
      "field": "key",
      "value": "REQ-001",
      "existing_resource_id": "item_req_001"
    }
  }
}
```

#### Concurrent Modification

```json
{
  "error": {
    "code": "CONFLICT",
    "message": "Resource was modified by another request",
    "details": {
      "resource_id": "item_req_001",
      "your_version": 5,
      "current_version": 6,
      "modified_by": "user_def456",
      "modified_at": "2024-01-20T10:30:00Z"
    }
  }
}
```

### Rate Limit Errors (429)

```json
{
  "error": {
    "code": "RATE_LIMITED",
    "message": "Rate limit exceeded. Please retry after 45 seconds.",
    "details": {
      "limit": 300,
      "window": "1 minute",
      "remaining": 0,
      "reset_at": "2024-01-20T10:31:00Z",
      "retry_after": 45
    }
  }
}
```

---

## Error Handling Best Practices

### 1. Check HTTP Status First

```python
import requests

response = requests.get(url, headers=headers)

if response.status_code == 200:
    data = response.json()
elif response.status_code == 401:
    handle_authentication_error()
elif response.status_code == 403:
    handle_permission_error()
elif response.status_code == 404:
    handle_not_found()
elif response.status_code == 429:
    handle_rate_limit(response)
elif response.status_code >= 500:
    handle_server_error(response)
else:
    handle_client_error(response)
```

### 2. Parse Error Details

```python
def handle_error(response):
    error_data = response.json().get("error", {})

    code = error_data.get("code")
    message = error_data.get("message")
    details = error_data.get("details", {})
    request_id = error_data.get("request_id")

    # Log for debugging
    logger.error(f"API Error [{code}]: {message}", extra={
        "request_id": request_id,
        "details": details
    })

    return code, message, details
```

### 3. Implement Retry Logic

```python
import time
import random

def request_with_retry(url, headers, max_retries=3):
    for attempt in range(max_retries):
        response = requests.get(url, headers=headers)

        if response.status_code == 429:
            retry_after = int(response.headers.get("Retry-After", 60))
            time.sleep(retry_after)
            continue

        if response.status_code >= 500:
            # Exponential backoff for server errors
            delay = min(2 ** attempt + random.uniform(0, 1), 60)
            time.sleep(delay)
            continue

        return response

    raise MaxRetriesExceeded()
```

### 4. Handle Validation Errors

```python
def handle_validation_error(error_details):
    errors = error_details.get("errors", [])

    field_errors = {}
    for error in errors:
        field = error.get("field")
        message = error.get("message")
        field_errors[field] = message

    return field_errors

# Usage
try:
    create_item(data)
except ValidationError as e:
    field_errors = handle_validation_error(e.details)
    for field, message in field_errors.items():
        print(f"{field}: {message}")
```

---

## SDK Error Handling

### Python

```python
from tracertm import TraceRTMClient
from tracertm.exceptions import (
    TraceRTMError,
    AuthenticationError,
    PermissionError,
    NotFoundError,
    ValidationError,
    RateLimitError,
    ServerError
)

client = TraceRTMClient(api_key="rtm_live_sk_...")

try:
    item = client.items.get(project_id="proj_abc123", item_id="item_req_001")

except AuthenticationError as e:
    print(f"Auth failed: {e.message}")
    # Refresh credentials or prompt for new API key

except PermissionError as e:
    print(f"Permission denied: {e.message}")
    print(f"Required: {e.details.get('required_permission')}")

except NotFoundError as e:
    print(f"Not found: {e.message}")
    # Handle missing resource

except ValidationError as e:
    print(f"Validation failed: {e.message}")
    for error in e.details.get("errors", []):
        print(f"  - {error['field']}: {error['message']}")

except RateLimitError as e:
    print(f"Rate limited. Retry after {e.retry_after} seconds")
    time.sleep(e.retry_after)
    # Retry request

except ServerError as e:
    print(f"Server error: {e.message}")
    print(f"Request ID: {e.request_id}")
    # Log and retry with backoff

except TraceRTMError as e:
    print(f"API error: {e.code} - {e.message}")
```

### TypeScript

```typescript
import { TraceRTMClient } from '@tracertm/sdk';
import {
  TraceRTMError,
  AuthenticationError,
  PermissionError,
  NotFoundError,
  ValidationError,
  RateLimitError,
  ServerError
} from '@tracertm/sdk/errors';

const client = new TraceRTMClient({ apiKey: 'rtm_live_sk_...' });

try {
  const item = await client.items.get({
    projectId: 'proj_abc123',
    itemId: 'item_req_001'
  });

} catch (error) {
  if (error instanceof AuthenticationError) {
    console.log(`Auth failed: ${error.message}`);

  } else if (error instanceof PermissionError) {
    console.log(`Permission denied: ${error.message}`);
    console.log(`Required: ${error.details?.requiredPermission}`);

  } else if (error instanceof NotFoundError) {
    console.log(`Not found: ${error.message}`);

  } else if (error instanceof ValidationError) {
    console.log(`Validation failed: ${error.message}`);
    for (const err of error.details?.errors || []) {
      console.log(`  - ${err.field}: ${err.message}`);
    }

  } else if (error instanceof RateLimitError) {
    console.log(`Rate limited. Retry after ${error.retryAfter} seconds`);
    await new Promise(r => setTimeout(r, error.retryAfter * 1000));

  } else if (error instanceof ServerError) {
    console.log(`Server error: ${error.message}`);
    console.log(`Request ID: ${error.requestId}`);

  } else if (error instanceof TraceRTMError) {
    console.log(`API error: ${error.code} - ${error.message}`);
  }
}
```

### Go

```go
package main

import (
    "context"
    "errors"
    "fmt"
    "time"
    "github.com/tracertm/tracertm-go"
)

func main() {
    client := tracertm.NewClient("rtm_live_sk_...")
    ctx := context.Background()

    item, err := client.Items.Get(ctx, "proj_abc123", "item_req_001")
    if err != nil {
        var authErr *tracertm.AuthenticationError
        var permErr *tracertm.PermissionError
        var notFoundErr *tracertm.NotFoundError
        var validationErr *tracertm.ValidationError
        var rateLimitErr *tracertm.RateLimitError
        var serverErr *tracertm.ServerError
        var apiErr *tracertm.APIError

        switch {
        case errors.As(err, &authErr):
            fmt.Printf("Auth failed: %s\n", authErr.Message)

        case errors.As(err, &permErr):
            fmt.Printf("Permission denied: %s\n", permErr.Message)
            fmt.Printf("Required: %s\n", permErr.Details["required_permission"])

        case errors.As(err, &notFoundErr):
            fmt.Printf("Not found: %s\n", notFoundErr.Message)

        case errors.As(err, &validationErr):
            fmt.Printf("Validation failed: %s\n", validationErr.Message)
            for _, e := range validationErr.Errors {
                fmt.Printf("  - %s: %s\n", e.Field, e.Message)
            }

        case errors.As(err, &rateLimitErr):
            fmt.Printf("Rate limited. Retry after %d seconds\n", rateLimitErr.RetryAfter)
            time.Sleep(time.Duration(rateLimitErr.RetryAfter) * time.Second)

        case errors.As(err, &serverErr):
            fmt.Printf("Server error: %s\n", serverErr.Message)
            fmt.Printf("Request ID: %s\n", serverErr.RequestID)

        case errors.As(err, &apiErr):
            fmt.Printf("API error: %s - %s\n", apiErr.Code, apiErr.Message)

        default:
            fmt.Printf("Unknown error: %v\n", err)
        }
        return
    }

    fmt.Printf("Item: %s\n", item.Title)
}
```

---

## Troubleshooting

### Getting Help

When contacting support, include:

1. **Request ID** - Found in error response
2. **Timestamp** - When the error occurred
3. **Endpoint** - The API URL called
4. **Request body** - Sanitized request data
5. **Response** - Complete error response

### Common Issues

| Symptom | Likely Cause | Solution |
|---------|--------------|----------|
| 401 on all requests | Invalid API key | Regenerate API key |
| 403 after working | Permissions changed | Check user permissions |
| 404 for known resource | Wrong project/ID | Verify project and resource IDs |
| 422 on create | Missing required fields | Check request body |
| 429 frequently | Too many requests | Implement rate limiting |
| 500 errors | Server issue | Check status page, retry |

---

## Related Documentation

- [Error Codes](/docs/api-reference/rest-api/error-codes) - Complete error code reference
- [Rate Limiting](/docs/api-reference/rest-api/rate-limiting) - Rate limit handling
- [Authentication](/docs/api-reference/authentication/overview) - API authentication
