Error Handling

Introduction

The Feedframer API uses standard HTTP status codes and follows the JSON:API error format for consistent, predictable error handling.

HTTP Status Codes

Status Code Meaning Description
200 OK Request succeeded
401 Unauthorized Missing or invalid API key
422 Unprocessable Entity Validation error (invalid parameters)
429 Too Many Requests Rate limit exceeded
500 Internal Server Error Server-side error
503 Service Unavailable Temporary service outage

Error Response Format

All errors follow the JSON:API specification:

{
  "errors": [
    {
      "status": "422",
      "code": "VALIDATION_ERROR",
      "title": "Validation Failed",
      "detail": "The page.size must be between 1 and 100.",
      "source": {
        "parameter": "page[size]"
      }
    }
  ]
}

Error Object Fields

Field Description
status HTTP status code as a string
code Machine-readable error code
title Short, human-readable summary
detail Detailed error message
source Optional pointer to the error source (parameter, field, etc.)

Common Errors

401 - Authentication Errors

Missing API Key

Cause: No api_key parameter provided

Response:

{
  "errors": [
    {
      "status": "401",
      "code": "MISSING_API_KEY",
      "title": "Authentication Required",
      "detail": "API key is required. Include it as a query parameter: ?api_key=YOUR_KEY"
    }
  ]
}

Solution:

# ❌ Missing API key
curl 'https://feedframer.com/api/v1/me'

# ✅ Include API key
curl 'https://feedframer.com/api/v1/me?api_key=YOUR_API_KEY'

Invalid API Key

Cause: API key is incorrect or has been regenerated

Response:

{
  "errors": [
    {
      "status": "401",
      "code": "INVALID_API_KEY",
      "title": "Authentication Failed",
      "detail": "The provided API key is invalid."
    }
  ]
}

Solution:

  • Verify your API key in your Instagram account settings
  • Check for typos or incomplete keys
  • Regenerate your API key if compromised

422 - Validation Errors

Invalid Page Size

Cause: page[size] parameter out of range (must be 1-100)

Response:

{
  "errors": [
    {
      "status": "422",
      "code": "VALIDATION_ERROR",
      "title": "Validation Failed",
      "detail": "The page.size must be between 1 and 100.",
      "source": {
        "parameter": "page[size]"
      }
    }
  ]
}

Solution:

# ❌ Invalid page size
curl 'https://feedframer.com/api/v1/me?api_key=YOUR_API_KEY&page[size]=150'

# ✅ Valid page size
curl 'https://feedframer.com/api/v1/me?api_key=YOUR_API_KEY&page[size]=100'

Invalid Post Type

Cause: filter[type] value is not a valid post type

Response:

{
  "errors": [
    {
      "status": "422",
      "code": "VALIDATION_ERROR",
      "title": "Validation Failed",
      "detail": "The filter.type must be one of: IMAGE, VIDEO, CAROUSEL_ALBUM, REELS.",
      "source": {
        "parameter": "filter[type]"
      }
    }
  ]
}

Solution:

# ❌ Invalid type
curl 'https://feedframer.com/api/v1/me?api_key=YOUR_API_KEY&filter[type]=PHOTO'

# ✅ Valid type
curl 'https://feedframer.com/api/v1/me?api_key=YOUR_API_KEY&filter[type]=IMAGE'

500 - Internal Server Error

Cause: Unexpected server error

Response:

{
  "errors": [
    {
      "status": "500",
      "code": "INTERNAL_SERVER_ERROR",
      "title": "Internal Server Error",
      "detail": "An unexpected error occurred. Please try again later."
    }
  ]
}

Solution:

  • Retry the request after a short delay
  • If the error persists, report it via GitHub Issues
  • Check status page for system issues

Error Handling Examples

JavaScript (Fetch API)

async function fetchPosts(apiKey) {
  try {
    const response = await fetch(
      `https://feedframer.com/api/v1/me?api_key=${apiKey}`
    );

    if (!response.ok) {
      const errorData = await response.json();
      const error = errorData.errors[0];

      switch (error.code) {
        case 'MISSING_API_KEY':
        case 'INVALID_API_KEY':
          throw new Error('Authentication failed. Check your API key.');

        case 'VALIDATION_ERROR':
          throw new Error(`Validation error: ${error.detail}`);

        default:
          throw new Error(`API error: ${error.detail}`);
      }
    }

    return await response.json();
  } catch (error) {
    console.error('Error fetching posts:', error.message);
    throw error;
  }
}

PHP

<?php

function fetchPosts($apiKey) {
    $url = "https://feedframer.com/api/v1/me?api_key={$apiKey}";

    $response = @file_get_contents($url);

    if ($response === false) {
        throw new Exception('Failed to connect to Feedframer API');
    }

    $data = json_decode($response, true);

    // Check for errors
    if (isset($data['errors'])) {
        $error = $data['errors'][0];

        switch ($error['code']) {
            case 'MISSING_API_KEY':
            case 'INVALID_API_KEY':
                throw new Exception('Authentication failed. Check your API key.');

            case 'VALIDATION_ERROR':
                throw new Exception('Validation error: ' . $error['detail']);

            default:
                throw new Exception('API error: ' . $error['detail']);
        }
    }

    return $data;
}

try {
    $posts = fetchPosts('YOUR_API_KEY');
    print_r($posts['data']);
} catch (Exception $e) {
    echo 'Error: ' . $e->getMessage();
}

Python

import requests

def fetch_posts(api_key):
    url = f'https://feedframer.com/api/v1/me?api_key={api_key}'

    try:
        response = requests.get(url)
        response.raise_for_status()  # Raises HTTPError for bad status codes
        return response.json()

    except requests.exceptions.HTTPError as e:
        error_data = e.response.json()
        error = error_data['errors'][0]

        if error['code'] in ['MISSING_API_KEY', 'INVALID_API_KEY']:
            raise Exception('Authentication failed. Check your API key.')

        elif error['code'] == 'VALIDATION_ERROR':
            raise Exception(f"Validation error: {error['detail']}")

        else:
            raise Exception(f"API error: {error['detail']}")

    except requests.exceptions.RequestException as e:
        raise Exception(f'Request failed: {str(e)}')

try:
    posts = fetch_posts('YOUR_API_KEY')
    print(posts['data'])
except Exception as e:
    print(f'Error: {e}')

Retry Strategies

Exponential Backoff

Retry failed requests with increasing delays:

async function fetchWithRetry(url, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch(url);

      if (response.status === 429) {
        // Rate limited - wait longer each time
        const delay = Math.pow(2, attempt) * 1000;
        console.log(`Rate limited. Retrying in ${delay}ms...`);
        await new Promise(resolve => setTimeout(resolve, delay));
        continue;
      }

      if (response.status >= 500) {
        // Server error - retry with backoff
        const delay = Math.pow(2, attempt) * 500;
        console.log(`Server error. Retrying in ${delay}ms...`);
        await new Promise(resolve => setTimeout(resolve, delay));
        continue;
      }

      // Success or client error (don't retry)
      return await response.json();

    } catch (error) {
      if (attempt === maxRetries) {
        throw error;
      }
      console.log(`Request failed. Retrying... (${attempt}/${maxRetries})`);
    }
  }

  throw new Error('Max retries exceeded');
}

Graceful Degradation

Provide fallback content when API fails:

async function fetchPostsWithFallback(apiKey) {
  try {
    return await fetchPosts(apiKey);
  } catch (error) {
    console.error('API error:', error);

    // Return cached data if available
    const cached = localStorage.getItem('cached_posts');
    if (cached) {
      console.log('Using cached data');
      return JSON.parse(cached);
    }

    // Return empty state
    return {
      data: [],
      message: 'Unable to load posts. Please try again later.'
    };
  }
}

GraphQL Errors

GraphQL errors have a different structure:

{
  "errors": [
    {
      "message": "Validation error",
      "extensions": {
        "category": "validation"
      },
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ]
    }
  ]
}

Handling GraphQL Errors:

const response = await fetch('https://feedframer.com/graphql?api_key=YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ query })
});

const result = await response.json();

if (result.errors) {
  const error = result.errors[0];
  console.error('GraphQL error:', error.message);
  // Handle error...
}

const posts = result.data.posts;

Best Practices

1. Always Check Response Status

if (!response.ok) {
  // Handle error
}

2. Parse Error Details

const errorData = await response.json();
const error = errorData.errors[0];
console.error(`Error ${error.code}: ${error.detail}`);

3. Implement Retry Logic

Retry transient errors (429, 500, 503) but not client errors (401, 422).

4. Log Errors for Debugging

console.error('API Error:', {
  status: error.status,
  code: error.code,
  detail: error.detail,
  timestamp: new Date().toISOString()
});

5. Provide User-Friendly Messages

const userMessage = error.code === 'VALIDATION_ERROR'
  ? `There was an issue with your request: ${error.detail}`
  : 'Unable to load Instagram posts. Please try again later.';

Error Codes Reference

Code Status Description
MISSING_API_KEY 401 API key not provided
INVALID_API_KEY 401 API key is invalid
VALIDATION_ERROR 422 Request validation failed
INTERNAL_SERVER_ERROR 500 Unexpected server error

Next Steps