Skip to main content

Overview

The Iris API uses standard HTTP status codes and structured response patterns to communicate errors. Understanding these patterns is essential for building robust integrations.

HTTP Status Codes

The API returns the following status codes:
200 OK
Success
Request processed successfully. Returns a JSON response with match results.
429 Too Many Requests
Rate Limit
Rate limit exceeded for your IP address. Slow down request frequency.
500 Internal Server Error
Server Error
Unexpected server error. Contact support if persistent.

Status Code Reference

CodeMeaningDescriptionAction Required
200OKRequest successful, results returnedNone
429Too Many RequestsRate limit exceededImplement backoff, reduce frequency
500Internal Server ErrorServer-side processing failureRetry with exponential backoff

Rate Limiting (429)

The API enforces strict rate limits to ensure fair usage and prevent abuse.

Rate Limit Configuration

The API implements per-IP rate limiting with the following parameters:
// From main.rs:127-129
let quota = Quota::per_second(NonZeroU32::new(5).unwrap())
    .allow_burst(NonZeroU32::new(10).unwrap());
Limits:
  • Sustained Rate: 5 requests per second per IP address
  • Burst Allowance: Up to 10 requests in a short burst
  • Scope: All endpoints (/compare, /stats, /health)
  • Enforcement: IP-based using the Governor library

Rate Limit Response

When rate limited, you’ll receive:
HTTP/1.1 429 Too Many Requests
Response Body: Empty (no JSON payload)
The API returns only the status code without additional error details. Your client must detect the 429 status and implement appropriate retry logic.

Handling Rate Limits

Implement these strategies to handle rate limiting gracefully:
class IrisClient {
  constructor(baseUrl) {
    this.baseUrl = baseUrl;
    this.maxRetries = 3;
  }

  async compareWithRetry(targetUrl, people, retryCount = 0) {
    try {
      const response = await fetch(`${this.baseUrl}/compare`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ target_url: targetUrl, people })
      });

      if (response.status === 429) {
        if (retryCount < this.maxRetries) {
          // Exponential backoff: 1s, 2s, 4s
          const delay = Math.pow(2, retryCount) * 1000;
          console.log(`Rate limited. Retrying in ${delay}ms...`);
          await new Promise(resolve => setTimeout(resolve, delay));
          return this.compareWithRetry(targetUrl, people, retryCount + 1);
        }
        throw new Error('Rate limit exceeded after max retries');
      }

      return await response.json();
    } catch (error) {
      throw new Error(`API request failed: ${error.message}`);
    }
  }
}

// Usage
const client = new IrisClient('http://localhost:8080');
try {
  const result = await client.compareWithRetry(
    'https://example.com/photo.jpg',
    [{ name: 'John Doe', image_url: 'https://example.com/john.jpg' }]
  );
  console.log('Matches:', result.matches);
} catch (error) {
  console.error('Error:', error.message);
}

Best Practices for Rate Limiting

1

Stay Under the Limit

Design your client to send no more than 4-5 requests per second, leaving headroom for burst traffic.
2

Implement Exponential Backoff

When receiving 429 responses, increase retry delays exponentially (1s, 2s, 4s, 8s).
3

Use Request Queuing

Queue requests client-side and process them at a controlled rate.
4

Monitor Rate Limit Errors

Track 429 responses to detect patterns and optimize request timing.
5

Consider Batch Processing

If comparing multiple targets, batch them strategically to minimize request count.

Empty Match Responses

The API returns successful responses (200 OK) even when no faces match or no faces are detected.

Empty Matches Scenarios

When the target image contains no detectable faces:
{
  "matches": []
}
Common Causes:
  • Image quality too low
  • Face occluded or at extreme angle
  • Face too small in the image
  • Image is not a face (landscape, object, etc.)
Code Reference: main.rs:87-89
let Some(t_emb) = target_embedding else {
    return Json(CompareResponse { matches: vec![] });
};
When faces are detected but none meet the similarity threshold:
{
  "matches": []
}
Matching Logic:
  • Similarity threshold: 0.363 (cosine similarity)
  • Only matches above threshold are returned
  • Results sorted by probability (descending)
Code Reference: main.rs:104
if score > 0.363 {
    results.push(MatchResult { ... });
}
When person images fail to download or decode, they’re silently skipped:
{
  "matches": []  // or partial matches if some succeeded
}
Silent Failure Behavior:
  • Individual person image failures don’t halt processing
  • Other valid images are still processed
  • No error details in response
Code Reference: main.rs:93
if let Ok(p_img) = download_and_decode(&person.image_url).await {
    // Process only if successful
}

Detecting Empty Response Causes

Since the API returns the same empty array for different failure modes, use these debugging strategies:
Test components individually:
// Test 1: Verify target image loads
const testTarget = await client.compare(
  'https://example.com/target.jpg',
  [{ name: 'Test', image_url: 'https://example.com/known-good.jpg' }]
);
// If empty, target image is the issue

// Test 2: Verify person images load
const testPerson = await client.compare(
  'https://example.com/known-good.jpg',
  [{ name: 'Test', image_url: person.image_url }]
);
// If empty, person image is the issue

// Test 3: Use known matching pair
const testMatch = await client.compare(
  'https://example.com/known-good.jpg',
  [{ name: 'Same Person', image_url: 'https://example.com/known-good.jpg' }]
);
// Should return high probability match

Image Decode Errors

Image processing failures occur silently but can be detected through careful testing.

Common Image Issues

Invalid Data URI

Malformed base64 data URIs missing comma separator.Error Location: main.rs:49
let comma = url.find(',').ok_or_else(
    || anyhow!("Invalid data URI")
)?;

Base64 Decode Failure

Corrupted or invalid base64 encoding.Error Location: main.rs:50
general_purpose::STANDARD.decode(&url[comma + 1..])?;

Image Decode Failure

Invalid image data or unsupported format.Error Location: main.rs:57
let img = imgcodecs::imdecode(&vector_uint8, imgcodecs::IMREAD_COLOR)?;

Empty Image

Image decoded but contains no pixel data.Error Location: main.rs:58
if img.empty() { return Err(anyhow!("Empty image")); }

Supported Image Formats

The API uses OpenCV’s imdecode function, which supports:
  • JPEG (.jpg, .jpeg)
  • PNG (.png)
  • BMP (.bmp)
  • TIFF (.tiff, .tif)
  • WebP (.webp)

Image URL Requirements

{
  "target_url": "https://example.com/photo.jpg",
  "people": [
    {
      "name": "Person 1",
      "image_url": "https://example.com/person1.jpg"
    }
  ]
}
Requirements:
  • Publicly accessible URLs
  • Must respond within reasonable timeout
  • Should return proper Content-Type headers
  • No authentication required (API can’t pass credentials)

Error Recovery Strategies

1

Validate Image URLs

Test URLs independently before sending to API:
curl -I https://example.com/photo.jpg
# Verify: HTTP 200, Content-Type: image/*, Content-Length > 0
2

Use Image CDNs

Host images on reliable CDN services (Cloudinary, imgix, AWS S3) to minimize download failures.
3

Implement Fallback Logic

async function compareWithFallback(target, people) {
  let result = await client.compare(target, people);
  
  if (result.matches.length === 0) {
    // Try alternative image URLs if available
    for (const person of people) {
      if (person.fallback_image_url) {
        person.image_url = person.fallback_image_url;
      }
    }
    result = await client.compare(target, people);
  }
  
  return result;
}
4

Optimize Image Quality

  • Resize images to reasonable dimensions (800x800 max)
  • Compress to reduce download time
  • Ensure faces are clearly visible and well-lit

Debugging Checklist

When troubleshooting API issues:

Error Response Examples

# HTTP Status: 429 Too Many Requests
# Body: Empty

# Detection in code:
if (response.status === 429) {
  console.log('Rate limited - slow down requests');
}

Getting Help

Check Server Logs

Review application logs for detailed error messages not exposed in API responses.

Test with Examples

Use working examples from the integration guide to verify your setup.

Verify Rate Limits

Check /stats endpoint to monitor your request patterns.

Image Guidelines

Review image requirements and best practices in the API reference.

Build docs developers (and LLMs) love