SCORM API Error Code Reference

SCORM API Error Code Reference

Overview

This document provides a comprehensive reference for all error codes returned by the SCORM API. Error codes are stable, machine-readable identifiers that can be used for programmatic error handling.

Error Response Format

All error responses follow this structure:

{
  "error": "Human-readable error message",
  "code": "ERROR_CODE",
  "details": {
    "field": "Additional context"
  }
}

HTTP Status Codes

CodeMeaningCommon Error Codes
200Success-
201Created-
400Bad RequestINVALID_REQUEST, MISSING_FILE, INVALID_FILE_TYPE, FILE_TOO_LARGE, MANIFEST_NOT_FOUND, PARSE_FAILED
401UnauthorizedUNAUTHORIZED, INVALID_API_KEY, EXPIRED_API_KEY
403ForbiddenFORBIDDEN, INSUFFICIENT_SCOPES, TENANT_MISMATCH, QUOTA_EXCEEDED, DISPATCH_NOT_ACTIVE
404Not FoundPACKAGE_NOT_FOUND, SESSION_NOT_FOUND, DISPATCH_NOT_FOUND, WEBHOOK_NOT_FOUND
409ConflictVERSION_CONFLICT, DUPLICATE_ENTRY
413Payload Too LargeFILE_TOO_LARGE
429Too Many RequestsRATE_LIMIT_EXCEEDED
500Internal Server ErrorINTERNAL_ERROR, DB_QUERY_FAILED, UPLOAD_FAILED, PARSE_FAILED
503Service UnavailableSERVICE_UNAVAILABLE, STORAGE_UNAVAILABLE

Authentication Errors

UNAUTHORIZED

HTTP Status: 401

Description: Request missing or invalid authentication credentials.

Causes:

  • Missing X-API-Key header
  • Invalid API key
  • Expired API key
  • Malformed authentication header

Resolution:

// Check API key is included
const response = await fetch(url, {
  headers: {
    'X-API-Key': apiKey // Ensure this is set
  }
});

// Verify API key is valid
if (response.status === 401) {
  // Regenerate API key or check expiration
}

INVALID_API_KEY

HTTP Status: 401

Description: The provided API key is invalid or has been revoked.

Resolution:

  • Verify API key is correct
  • Check if key was revoked
  • Generate a new API key if needed

EXPIRED_API_KEY

HTTP Status: 401

Description: The API key has expired.

Resolution:

  • Generate a new API key
  • Update your application with the new key

FORBIDDEN

HTTP Status: 403

Description: Request authenticated but lacks required permissions.

Causes:

  • API key doesn't have required scopes
  • Attempting to access another tenant's data
  • Resource access denied

Resolution:

  • Verify API key has required scopes (read/write/admin)
  • Check tenant_id matches API key's tenant
  • Request appropriate scopes if needed

INSUFFICIENT_SCOPES

HTTP Status: 403

Description: API key doesn't have required scope for this operation.

Example:

  • Attempting POST with read-only API key
  • Attempting DELETE without admin scope

Resolution:

  • Use API key with appropriate scopes
  • Request scope upgrade if needed

Request Validation Errors

INVALID_REQUEST

HTTP Status: 400

Description: Request body or parameters are invalid.

Common Causes:

  • Missing required fields
  • Invalid data types
  • Validation rule violations

Example Response:

{
  "error": "Invalid request parameters",
  "code": "INVALID_REQUEST",
  "details": {
    "field": "tenant_id",
    "message": "tenant_id is required"
  }
}

Resolution:

  • Review request body against API documentation
  • Check all required fields are present
  • Validate data types match expected format

MISSING_FILE

HTTP Status: 400

Description: File upload request missing file data.

Resolution:

// Ensure file is included in FormData
const formData = new FormData();
formData.append('file', fileBlob); // Required
formData.append('tenant_id', tenantId);
formData.append('uploaded_by', userId);

INVALID_FILE_TYPE

HTTP Status: 400

Description: Uploaded file is not a valid ZIP archive.

Resolution:

  • Ensure file is a .zip archive
  • Verify file is not corrupted
  • Check file extension matches content

FILE_TOO_LARGE

HTTP Status: 400 or 413

Description: Uploaded file exceeds maximum size limit (default 10GB).

Details:

{
  "error": "File too large. Your file is 12GB, but the maximum size is 10GB",
  "code": "FILE_TOO_LARGE",
  "details": {
    "file_size_gb": 12,
    "max_size_gb": 10
  }
}

Resolution:

  • Reduce file size (compress assets, remove unused files)
  • Use multipart upload for large files
  • Request quota increase if justified

Resource Errors

PACKAGE_NOT_FOUND

HTTP Status: 404

Description: Requested package does not exist or is not accessible.

Causes:

  • Package ID doesn't exist
  • Package belongs to different tenant
  • Package was deleted

Resolution:

// Verify package ID is correct
const package = await getPackage(packageId);

// Check tenant access
if (!package || package.tenant_id !== tenantId) {
  // Package not found or access denied
}

SESSION_NOT_FOUND

HTTP Status: 404

Description: Requested session does not exist or is not accessible.

Resolution:

  • Verify session ID is correct
  • Check session belongs to your tenant
  • Ensure session wasn't deleted

DISPATCH_NOT_FOUND

HTTP Status: 404

Description: Requested dispatch package does not exist.

Resolution:

  • Verify dispatch ID is correct
  • Check dispatch belongs to your tenant
  • Ensure dispatch wasn't deleted

WEBHOOK_NOT_FOUND

HTTP Status: 404

Description: Requested webhook does not exist.

Resolution:

  • Verify webhook ID is correct
  • Check webhook belongs to your tenant

Conflict Errors

VERSION_CONFLICT

HTTP Status: 409

Description: Optimistic locking conflict - session was updated by another client.

Response:

{
  "error": "Version conflict detected. Another update was made to this session.",
  "code": "VERSION_CONFLICT",
  "current_version": 2,
  "message": "Please fetch the latest session data and retry your update."
}

Resolution:

async function updateSessionWithRetry(sessionId: string, updates: any) {
  for (let attempt = 0; attempt < 3; attempt++) {
    // Get latest session
    const session = await getSession(sessionId);
    
    // Merge updates
    const merged = { ...session.cmi_data, ...updates.cmi_data };
    
    // Update with current version
    try {
      return await updateSession(sessionId, {
        ...updates,
        cmi_data: merged,
        version: session.version
      });
    } catch (error) {
      if (error.code === 'VERSION_CONFLICT' && attempt < 2) {
        continue; // Retry
      }
      throw error;
    }
  }
}

DUPLICATE_ENTRY

HTTP Status: 409

Description: Attempting to create a resource that already exists.

Resolution:

  • Check if resource already exists
  • Use update endpoint if resource exists
  • Use unique identifiers

Quota Errors

QUOTA_EXCEEDED

HTTP Status: 403

Description: Tenant quota limit exceeded.

Types:

  • TENANT_PACKAGE_LIMIT: Package count quota exceeded
  • TENANT_STORAGE_LIMIT: Storage quota exceeded

Response:

{
  "error": "Storage quota exceeded. Used: 50 GB / Limit: 50 GB",
  "code": "QUOTA_EXCEEDED",
  "details": {
    "quota_type": "storage",
    "limit": 53687091200,
    "used": 53687091200,
    "required": 1048576000,
    "available": 0
  }
}

Resolution:

  • Delete unused packages
  • Request quota increase
  • Optimize package sizes
  • Archive old packages

Rate Limiting Errors

RATE_LIMIT_EXCEEDED

HTTP Status: 429

Description: Rate limit exceeded for tenant.

Response:

{
  "error": "Rate limit exceeded",
  "code": "RATE_LIMIT_EXCEEDED",
  "details": {
    "limit": 1000,
    "remaining": 0,
    "reset_at": "2025-01-12T10:00:00Z",
    "retry_after_seconds": 3600
  }
}

Headers:

Retry-After: 3600
X-RateLimit-Reset: 1640995200

Resolution:

  • Wait for rate limit window to reset
  • Implement exponential backoff
  • Reduce request frequency
  • Use webhooks instead of polling

Processing Errors

PARSE_FAILED

HTTP Status: 400 or 500

Description: Failed to parse SCORM manifest or package structure.

Causes:

  • Invalid or corrupted manifest XML
  • Missing required manifest elements
  • Unsupported SCORM version

Resolution:

  • Validate SCORM package before upload
  • Check manifest XML is well-formed
  • Ensure package follows SCORM specification

MANIFEST_NOT_FOUND

HTTP Status: 400

Description: imsmanifest.xml not found in package.

Resolution:

  • Ensure package contains imsmanifest.xml at root
  • Verify package structure is correct
  • Check package is not corrupted

UPLOAD_FAILED

HTTP Status: 500

Description: Failed to upload file to storage.

Causes:

  • Storage service unavailable
  • Network connectivity issues
  • Storage quota exceeded

Resolution:

  • Retry with exponential backoff
  • Check storage service status
  • Verify storage configuration
  • Check storage quota

Database Errors

DB_QUERY_FAILED

HTTP Status: 500

Description: Database query failed.

Causes:

  • Database connection issues
  • Query timeout
  • Constraint violations
  • RLS policy violations

Resolution:

  • Retry with exponential backoff
  • Check database connectivity
  • Verify RLS policies are configured
  • Review query parameters

DB_INSERT_FAILED

HTTP Status: 500

Description: Failed to insert record into database.

Resolution:

  • Check required fields are provided
  • Verify data types match schema
  • Check for constraint violations
  • Retry if transient error

Dispatch Errors

DISPATCH_NOT_ACTIVE

HTTP Status: 403

Description: Dispatch package is not active (expired or revoked).

Resolution:

  • Check dispatch expiration date
  • Verify dispatch is not revoked
  • Create new dispatch if expired

REGISTRATION_LIMIT_EXCEEDED

HTTP Status: 403

Description: Dispatch registration limit reached.

Resolution:

  • Check registration count
  • Increase registration limit if needed
  • Create new dispatch for additional registrations

LICENSE_LIMIT_EXCEEDED

HTTP Status: 403

Description: Dispatch license limit reached.

Resolution:

  • Check license count
  • Increase license limit if needed
  • Verify unique user tracking

Webhook Errors

WEBHOOK_DELIVERY_FAILED

HTTP Status: 500

Description: Failed to deliver webhook event.

Causes:

  • Webhook URL unreachable
  • Webhook server error
  • Network timeout
  • Invalid webhook signature

Resolution:

  • Verify webhook URL is accessible
  • Check webhook server logs
  • Verify HMAC signature verification
  • System will retry automatically

SCORM API Errors (Player)

SCORM 1.2 Error Codes

CodeDescription
0No error
101General exception
201Invalid argument error
202Element cannot have children
203Element not an array - cannot have count
301Not initialized
401Not implemented error
402Invalid set value, element is a keyword
403Element is read only
404Element is write only
405Data model element value not initialized

SCORM 2004 Error Codes

CodeDescription
0No error
101General exception
102General initialization failure
103Already initialized
104Content instance terminated
111General termination failure
112Termination before initialization
113Termination after termination
122Retrieve data before initialization
123Retrieve data after termination
132Store data before initialization
133Store data after termination
142Commit before initialization
143Commit after termination
201Invalid argument error
301General get failure
351General set failure
391General commit failure
401Undefined data model element
402Unimplemented data model element
403Data model element value not initialized
404Data model element is read only
405Data model element is write only
406Data model element type mismatch
407Data model element value out of range
408Data model dependency not established

Error Handling Best Practices

1. Check Error Codes

const response = await fetch(url, options);
const data = await response.json();

if (!response.ok) {
  switch (data.code) {
    case 'VERSION_CONFLICT':
      // Retry with fresh data
      return retryUpdate();
    case 'RATE_LIMIT_EXCEEDED':
      // Wait and retry
      await wait(data.details.retry_after_seconds);
      return retry();
    case 'QUOTA_EXCEEDED':
      // Handle quota limit
      throw new QuotaExceededError(data);
    default:
      throw new APIError(data);
  }
}

2. Implement Retry Logic

async function requestWithRetry(url: string, options: RequestInit, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);
      
      // Don't retry client errors (4xx) except 409
      if (response.status >= 400 && response.status < 500 && response.status !== 409) {
        return response;
      }
      
      // Retry server errors (5xx) and 409 conflicts
      if (response.ok || (response.status !== 500 && response.status !== 503 && response.status !== 409)) {
        return response;
      }
      
      // Exponential backoff
      const delay = Math.pow(2, attempt) * 1000;
      await new Promise(resolve => setTimeout(resolve, delay));
    } catch (error) {
      if (attempt === maxRetries - 1) throw error;
      const delay = Math.pow(2, attempt) * 1000;
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
  throw new Error('Max retries exceeded');
}

3. Log Errors for Debugging

function handleError(error: APIError) {
  console.error('API Error:', {
    code: error.code,
    message: error.message,
    details: error.details,
    status: error.status,
    request_id: error.request_id
  });
  
  // Send to error tracking service
  errorTracker.captureException(error);
}

Error Code Categories

Client Errors (4xx)

  • Authentication: UNAUTHORIZED, INVALID_API_KEY, FORBIDDEN
  • Validation: INVALID_REQUEST, MISSING_FILE, INVALID_FILE_TYPE
  • Resources: PACKAGE_NOT_FOUND, SESSION_NOT_FOUND
  • Conflicts: VERSION_CONFLICT, DUPLICATE_ENTRY
  • Quotas: QUOTA_EXCEEDED
  • Rate Limits: RATE_LIMIT_EXCEEDED

Server Errors (5xx)

  • Processing: PARSE_FAILED, UPLOAD_FAILED
  • Database: DB_QUERY_FAILED, DB_INSERT_FAILED
  • Services: SERVICE_UNAVAILABLE, STORAGE_UNAVAILABLE
  • General: INTERNAL_ERROR

Last Updated: 2025-01-12
Version: 1.0

For error handling examples, see Error Handling Guide.