Introduction

Batch API operations allow multiple requests to be combined into a single HTTP call, improving efficiency by reducing network overhead. However, batch operations can partially succeed when some items in the batch fail while others succeed. This partial failure scenario requires careful handling to identify which items failed, understand why, and implement appropriate retry or error handling logic. Without proper error handling, partial failures can lead to data inconsistency, missed operations, or silent failures in client applications.

Symptoms

When a batch API request partially fails, you will observe:

  • HTTP 207 Multi-Status response indicating mixed results
  • Response body contains individual item statuses with some errors
  • Client application shows incomplete data or missing records
  • Audit logs show some operations succeeded while others failed
  • Dashboard metrics show discrepancy between expected and actual operations

Typical response format for partial failure:

json
{
  "responses": [
    {
      "id": "item-001",
      "status": 200,
      "data": {"result": "success"}
    },
    {
      "id": "item-002",
      "status": 400,
      "error": {
        "code": "VALIDATION_ERROR",
        "message": "Invalid email format"
      }
    },
    {
      "id": "item-003",
      "status": 403,
      "error": {
        "code": "PERMISSION_DENIED",
        "message": "Insufficient permissions for resource"
      }
    }
  ],
  "summary": {
    "total": 3,
    "succeeded": 1,
    "failed": 2
  }
}

Or in XML format for SOAP APIs: ``xml <BatchResponse> <CreateResponse id="item-001" status="success"/> <CreateResponse id="item-002" status="failure"> <Error>Validation failed: duplicate key</Error> </CreateResponse> </BatchResponse>

Common Causes

  1. 1.Validation errors - Some items have invalid data that fails server-side validation
  2. 2.Permission issues - Client lacks permissions for specific resources but not others
  3. 3.Rate limiting - Batch exceeds rate limits partway through processing
  4. 4.Resource conflicts - Unique constraint violations or concurrent modifications
  5. 5.Missing dependencies - Referenced resources don't exist for some items
  6. 6.Data type mismatches - Field values have incorrect types for some items
  7. 7.Payload size limits - Batch size exceeds server limits mid-processing
  8. 8.Idempotency conflicts - Duplicate requests with different results
  9. 9.Backend failures - Upstream service errors affect subset of operations
  10. 10.Timeout during processing - Long-running batches timeout partially

Step-by-Step Fix

Step 1: Parse and Analyze Batch Response

Examine the batch response to identify failed items:

```bash # Using jq to parse batch response curl -s -X POST https://api.example.com/batch \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d @batch-request.json | jq '.'

# Extract failed items curl -s https://api.example.com/batch -d @request.json | \ jq '.responses[] | select(.status >= 400)'

# Get summary statistics curl -s https://api.example.com/batch -d @request.json | \ jq '.summary' ```

Python example for parsing: ```python import requests

response = requests.post( 'https://api.example.com/batch', headers={'Authorization': f'Bearer {token}'}, json=batch_items )

if response.status_code == 207: results = response.json() failed_items = [ r for r in results['responses'] if r['status'] >= 400 ] for item in failed_items: print(f"Item {item['id']} failed: {item['error']['message']}") ```

Step 2: Identify Failure Categories

Group failures by error type for targeted resolution:

```python from collections import defaultdict

def categorize_failures(batch_response): failures_by_type = defaultdict(list)

for item in batch_response['responses']: if item['status'] >= 400: error_code = item['error']['code'] failures_by_type[error_code].append(item)

return failures_by_type

# Example output: # { # 'VALIDATION_ERROR': [item-002, item-005], # 'PERMISSION_DENIED': [item-003], # 'RATE_LIMITED': [item-007, item-008, item-009] # } ```

Step 3: Handle Validation Errors

Fix validation errors in failed items:

```bash # Check validation rules for specific endpoint curl -s https://api.example.com/docs/validation/users | jq '.'

# Validate individual item before retry curl -s -X POST https://api.example.com/users/validate \ -H "Authorization: Bearer $TOKEN" \ -d '{"email": "invalid-email", "name": "John"}' ```

Common validation fixes: ```python def fix_validation_errors(item, error_message): if 'email' in error_message.lower(): # Fix email format item['email'] = item['email'].strip().lower() if '@' not in item['email']: item['email'] = f"{item['name'].lower()}@example.com"

if 'date' in error_message.lower(): # Fix date format item['date'] = datetime.strptime(item['date'], '%m/%d/%Y').isoformat()

return item ```

Step 4: Handle Permission Errors

Check and request necessary permissions:

```bash # Check current user permissions curl -s https://api.example.com/auth/permissions \ -H "Authorization: Bearer $TOKEN" | jq '.'

# Check specific resource permissions curl -s https://api.example.com/resources/item-003/permissions \ -H "Authorization: Bearer $TOKEN" | jq '.' ```

Filter out items requiring elevated permissions: ```python def filter_by_permission(batch_items, token): allowed_items = [] permission_denied = []

for item in batch_items: # Check if user can access the resource check_url = f"https://api.example.com/resources/{item['resource_id']}/check-access" response = requests.get(check_url, headers={'Authorization': f'Bearer {token}'})

if response.status_code == 200: allowed_items.append(item) else: permission_denied.append(item)

return allowed_items, permission_denied ```

Step 5: Implement Retry Logic for Rate Limits

Handle rate limiting with exponential backoff:

```python import time import random

def retry_batch_with_backoff(batch_items, api_url, token, max_retries=5): base_delay = 1 # seconds

for attempt in range(max_retries): response = requests.post( api_url, headers={'Authorization': f'Bearer {token}'}, json={'items': batch_items} )

if response.status_code == 200: return response.json()

if response.status_code == 429: # Rate limited - get retry-after header retry_after = response.headers.get('Retry-After', base_delay * (2 ** attempt)) delay = int(retry_after) + random.uniform(0, 1) print(f"Rate limited. Waiting {delay}s before retry...") time.sleep(delay) continue

if response.status_code == 207: # Partial success - retry only failed items results = response.json() batch_items = [ item for item, resp in zip(batch_items, results['responses']) if resp['status'] >= 400 and resp['error']['code'] == 'RATE_LIMITED' ] if not batch_items: return results # All non-rate-limit errors handled delay = base_delay * (2 ** attempt) + random.uniform(0, 1) time.sleep(delay) continue

# Other error response.raise_for_status()

raise Exception("Max retries exceeded") ```

Step 6: Process Individual Items as Fallback

If batch continues to fail, process items individually:

```python def process_individually(items, api_url, token): results = {'succeeded': [], 'failed': []}

for item in items: try: response = requests.post( f"{api_url}/items", headers={'Authorization': f'Bearer {token}'}, json=item ) response.raise_for_status() results['succeeded'].append({'id': item['id'], 'data': response.json()}) except requests.exceptions.RequestException as e: results['failed'].append({ 'id': item['id'], 'error': str(e), 'item': item # Keep original for retry })

# Rate limit protection time.sleep(0.1) # 100ms between requests

return results ```

Step 7: Reconstruct and Retry Failed Items

Create a new batch with only corrected failed items:

```bash # Extract failed items from previous batch curl -s https://api.example.com/batch-results/12345 | \ jq '.responses[] | select(.status >= 400) | .request' > failed-items.json

# Apply corrections and retry jq 'map(.email = .email | ascii_downcase)' failed-items.json > corrected-items.json

# Submit corrected batch curl -X POST https://api.example.com/batch \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d @corrected-items.json ```

Verification

After processing, verify all items were handled:

```bash # Check batch result summary curl -s https://api.example.com/batch-results/12345 | \ jq '.summary | "Succeeded: \(.succeeded)/\(.total), Failed: \(.failed)/\(.total)"'

# Verify individual items exist for id in item-001 item-002 item-003; do curl -s -o /dev/null -w "$id: %{http_code}\n" \ "https://api.example.com/items/$id" \ -H "Authorization: Bearer $TOKEN" done ```

Expected output: `` item-001: 200 item-002: 200 item-003: 200

Validate data consistency: ```python def verify_batch_consistency(batch_request, batch_response): """Verify all items were processed correctly.""" requested_ids = {item['id'] for item in batch_request['items']} succeeded_ids = { r['id'] for r in batch_response['responses'] if r['status'] < 400 }

missing = requested_ids - succeeded_ids if missing: print(f"Warning: {len(missing)} items not processed: {missing}") return False return True ```

Prevention

To prevent partial batch failures:

  1. 1.Pre-validate items - Validate all items before sending batch:
  2. 2.```python
  3. 3.def validate_before_batch(items, schema):
  4. 4.valid_items = []
  5. 5.for item in items:
  6. 6.try:
  7. 7.validate(item, schema)
  8. 8.valid_items.append(item)
  9. 9.except ValidationError as e:
  10. 10.log_validation_error(item, e)
  11. 11.return valid_items
  12. 12.`
  13. 13.Check permissions upfront - Verify access to all resources:
  14. 14.```bash
  15. 15.# Batch permission check
  16. 16.curl -X POST https://api.example.com/auth/check-batch \
  17. 17.-H "Authorization: Bearer $TOKEN" \
  18. 18.-d '{"resources": ["res-1", "res-2", "res-3"]}'
  19. 19.`
  20. 20.Use idempotency keys - Enable safe retries:
  21. 21.```python
  22. 22.import uuid

def add_idempotency_keys(items): for item in items: item['idempotency_key'] = str(uuid.uuid4()) return items ```

  1. 1.Implement chunking - Split large batches:
  2. 2.```python
  3. 3.def chunk_batch(items, chunk_size=100):
  4. 4.for i in range(0, len(items), chunk_size):
  5. 5.yield items[i:i + chunk_size]
  6. 6.`
  7. 7.Add client-side rate limiting:
  8. 8.```python
  9. 9.from ratelimit import limits, sleep_and_retry

@sleep_and_retry @limits(calls=10, period=1) # 10 calls per second def submit_batch_chunk(chunk, api_url, token): return requests.post(api_url, headers={'Authorization': f'Bearer {token}'}, json={'items': chunk}) ```

  1. 1.Monitor batch success rates:
  2. 2.```python
  3. 3.def track_batch_metrics(batch_response):
  4. 4.success_rate = batch_response['summary']['succeeded'] / batch_response['summary']['total']
  5. 5.if success_rate < 0.9: # Alert if < 90% success
  6. 6.alert_low_batch_success(success_rate, batch_response)
  7. 7.`
  8. 8.Implement circuit breaker - Stop processing if failure rate is high:
  9. 9.```python
  10. 10.class BatchCircuitBreaker:
  11. 11.def __init__(self, failure_threshold=0.5, window_size=10):
  12. 12.self.failures = []
  13. 13.self.failure_threshold = failure_threshold
  14. 14.self.window_size = window_size

def should_proceed(self): if len(self.failures) < self.window_size: return True recent_failure_rate = sum(self.failures[-self.window_size:]) / self.window_size return recent_failure_rate < self.failure_threshold ```

  • [WordPress troubleshooting: Fix IAM Permission Denied - Complete Tro](fix-iam-permission-denied-d4at)
  • [WordPress troubleshooting: Fix IAM Access Denied 403 - Complete Tro](fix-iam-access-denied-403-ywdw)
  • [WordPress troubleshooting: Fix ELB Permission Denied - Complete Tro](fix-elb-permission-denied-1h5w)
  • [WordPress troubleshooting: Fix IAM Timeout Error - Complete Trouble](fix-iam-timeout-error-i8br)
  • [WordPress troubleshooting: Fix IAM Access Denied 403 - Complete Tro](fix-iam-access-denied-403-5gzy)

<script type="application/ld+json"> { "@context": "https://schema.org", "@type": "TechArticle", "headline": "API Batch Request Partial Failure", "description": "Fix batch API partial failures by handling individual item errors, implementing retry logic, and validating batch requests.", "url": "https://www.fixwikihub.com/fix-api-batch-request-partial-failure", "publisher": { "@type": "Organization", "name": "FixWikiHub", "url": "https://www.fixwikihub.com" }, "author": { "@type": "Person", "name": "FixWikiHub Editorial Team" }, "datePublished": "2025-12-13T01:43:31.210Z", "dateModified": "2025-12-13T01:43:31.210Z" } </script>