Error handling

Understanding and handling API errors effectively.

Last updated 8 months ago

HTTP Status Codes

Code

Meaning

Description

200

OK

Request successful

202

Accepted

Task created successfully

400

Bad Request

Invalid request data

401

Unauthorized

Invalid or missing API key

403

Forbidden

Access denied to resource

404

Not Found

Resource not found

409

Conflict

Task already running

422

Unprocessable Entity

Validation failed

429

Too Many Requests

Rate limit exceeded

500

Internal Server Error

Server error

Error Response Format

All errors return a consistent JSON structure:

{
  "detail": "error_code_or_message"
}

Common Errors

401 Unauthorized

Missing API Key:

{
  "detail": "missing_api_key"
}

Invalid API Key:

{
  "detail": "invalid_api_key"
}

Solution: Check your API key is correct and included in the X-API-Key header.

403 Forbidden

No Workspace Access:

{
  "detail": "user_not_in_workspace"
}

Solution: Verify you have access to the workspace ID you're using.

409 Conflict

Duplicate Task:

{
  "detail": "task_blocked_by_another_task"
}

Solution: A collection task is already running for this post. Wait for completion or check task status.

422 Validation Error

Validation errors provide detailed field-level feedback:

Invalid LinkedIn URL:

{
  "detail": [
    {
      "type": "value_error",
      "loc": ["body", "post_url"],
      "msg": "Invalid LinkedIn post URL format",
      "input": "https://example.com/invalid-url"
    }
  ]
}

Missing Required Field:

{
  "detail": [
    {
      "type": "missing",
      "loc": ["body", "workspace_id"],
      "msg": "Field required",
      "input": {
        "post_url": "https://linkedin.com/posts/example",
        "data_types": ["comment"]
      }
    }
  ]
}

Invalid Data Types:

{
  "detail": [
    {
      "type": "value_error",
      "loc": ["body", "data_types"],
      "msg": "Input should be 'comment' or 'reaction'",
      "input": ["invalid_type"]
    }
  ]
}

429 Rate Limit Exceeded

{
  "detail": "Rate limit exceeded"
}

Domain-Specific Errors

Invalid Activity Filter

{
  "detail": "Invalid activity types: invalid_type. Valid options: posters, commenters, reactors"
}

Temporary Workbook Only

{
  "detail": "Currently only supports temporary workbooks. Use the export feature for permanent workbooks."
}

Task Not Found

{
  "detail": "task_not_found"
}

Error Handling Best Practices

1. Always Check Status Codes

import requests

response = requests.post(url, json=data, headers=headers)
if response.status_code == 422:
    validation_errors = response.json()["detail"]
    for error in validation_errors:
        print(f"Field {error['loc']}: {error['msg']}")
elif response.status_code == 409:
    print("Task already running, check status instead")
elif response.status_code == 403:
    print("Access denied - check workspace permissions")

2. Handle Rate Limits Gracefully

import time

def make_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))
            print(f"Rate limited, waiting {retry_after} seconds...")
            time.sleep(retry_after)
            continue
            
        return response
    
    raise Exception("Max retries exceeded")

3. Validate Data Before Sending

import re

def validate_linkedin_url(url):
    patterns = [
        r'https://www\.linkedin\.com/posts/\w+_activity-\d+',
        r'https://www\.linkedin\.com/feed/update/urn:li:activity:\d+'
    ]
    return any(re.match(pattern, url) for pattern in patterns)

def validate_payload(payload):
    if not validate_linkedin_url(payload['post_url']):
        raise ValueError("Invalid LinkedIn URL format")
    
    valid_types = {'comment', 'reaction'}
    if not set(payload['data_types']).issubset(valid_types):
        raise ValueError(f"Invalid data types. Valid: {valid_types}")

4. Handle Task Failures

def wait_for_task_completion(task_id, headers, timeout=300):
    start_time = time.time()
    
    while time.time() - start_time < timeout:
        response = requests.get(f"/tasks/{task_id}/status", headers=headers)
        data = response.json()
        
        if data["status"] == "success":
            return data["result"]
        elif data["status"] == "failure":
            raise Exception(f"Task failed: {data.get('error', 'Unknown error')}")
        
        time.sleep(10)
    
    raise TimeoutError("Task did not complete within timeout")

Debugging Tips

1. Enable Verbose Logging

Log all requests and responses during development:

import logging
import requests

logging.basicConfig(level=logging.DEBUG)
response = requests.post(url, json=data, headers=headers)
print(f"Status: {response.status_code}")
print(f"Response: {response.text}")

2. Test with curl First

Verify your requests work with curl before implementing in code:

curl -v -H "X-API-Key: test_key" \
     -H "Content-Type: application/json" \
     -d '{"post_url": "https://linkedin.com/posts/test", "data_types": ["comment"], "workspace_id": "test_workspace"}' \
     https://production.viacurrent.com/api/workbooks/

3. Common Validation Issues

Data Types:

  • ["comment"], ["reaction"], ["comment", "reaction"]

  • ["comments"], ["reactions"], ["likes"]

Workspace ID:

  • "507f1f77bcf86cd799439011" (valid ObjectId string)

  • null, "", "invalid-id"