Membership API Error Handling Guide
Membership API Error Handling Guide
Overview
This document provides comprehensive guidance for handling errors returned by the ICHRA Membership API. It is intended for developers integrating with Oscar's ICHRA API and serves as the authoritative reference for error codes, their meanings, and recommended handling strategies.
Purpose
When your API requests encounter issues, the Membership API returns structured error responses with machine-readable error codes. This guide helps you:
- Understand error responses - Learn the structure and fields of error responses
- Categorize errors - Determine whether an error is fixable, retryable, or requires escalation
- Implement error handling - Build robust error handling logic in your integration
- Resolve issues quickly - Use the error code reference to diagnose and fix problems
How to Use This Guide
- During development: Reference the Error Code Reference section to understand specific errors you encounter
- When building integrations: Use the Error Categories section to implement proper error handling logic
- For transient failures: Follow the Retry Strategy section for handling temporary errors
- When contacting support: Include the
application_idanderror_codefrom your error response
Quick Reference
| I need to... | Go to section |
|---|---|
| Understand an error code | Error Code Reference |
| Know if I should retry | Error Categories |
| Implement retry logic | Retry Strategy |
| See example responses | Example Error Responses |
| Add error handling code | Handling Errors in Code |
Applicable Endpoints
This guide covers error handling for the ICHRA Membership API endpoints:
POST /memberships/create-membershipPOST /memberships/update-membership
Error Response Structure
All processing errors return a consistent JSON structure:
{
"application_id": "123abc987def456fed789cba432bcdaa",
"enrollees": [],
"message": "The request could not be processed due to validation errors.",
"errors": [
{
"error_code": "INVALID_SSN_FORMAT",
"message": "The SSN provided is invalid. Please verify and resubmit."
}
]
}Response Fields
| Field | Type | Description |
|---|---|---|
application_id | string | null | The enrollment ID for this request. Retain this value for troubleshooting with Oscar support. May be null if the error occurred before enrollment creation. |
enrollees | array | Empty array on error responses. |
message | string | Human-readable summary of the error category. |
errors | array | List of structured error objects (see below). |
Error Object Fields
| Field | Type | Description |
|---|---|---|
error_code | string | Machine-readable error code for programmatic handling. |
message | string | Human-readable description of the specific error. |
Note: The field property is not included in error responses. Use the error_code and message to identify and resolve issues.
Error Categories
Errors are classified into three categories based on the HTTP status code returned:
| Category | HTTP Code | Description | Action |
|---|---|---|---|
| ACTIONABLE | 400 | Validation or data errors that can be fixed by the client | Fix the request data and retry |
| RETRY | 503 | Transient errors due to temporary conditions | Retry with exponential backoff |
| ESCALATE | 500 | Internal errors requiring Oscar intervention | Contact Oscar support with application_id |
Retry Strategy
When to Retry
Only retry requests that return HTTP 503 with RETRY category errors:
| Error Code | Retry? | Strategy |
|---|---|---|
| ACTIONABLE (400) | No | Fix request data first |
| RETRY (503) | Yes | Exponential backoff |
| ESCALATE (500) | No | Contact Oscar support |
Recommended Retry Logic
import time
import random
def retry_with_backoff(request_func, max_retries=3):
"""Retry a request with exponential backoff."""
for attempt in range(max_retries):
response = request_func()
if response.status_code != 503:
return response
# Exponential backoff with jitter
wait_time = (2 ** attempt) + random.uniform(0, 1)
time.sleep(wait_time)
return response # Return last response after all retries| Attempt | Wait Time |
|---|---|
| 1 | 1-2 seconds |
| 2 | 2-3 seconds |
| 3 | 4-5 seconds |
Error Code Reference
Request Validation Errors
These errors indicate problems with the request format or field values.
| Error Code | Message | Resolution |
|---|---|---|
INVALID_REQUEST_FORMAT | The request contains invalid data. Please review and correct the submission. | Review the request structure against the API specification. |
MISSING_REQUIRED_FIELD | A required field is missing. | Check the error message for details on the missing field. |
INVALID_FIELD_VALUE | The field value is invalid. | Verify the field value matches the expected format or enum. |
INVALID_DATE_FORMAT | The date format is invalid. | Use YYYY-MM-DD format for all dates. |
INVALID_EMAIL_FORMAT | The provided email address is invalid. | Verify the email address format. |
INVALID_SSN_FORMAT | The SSN provided is invalid. Please verify and resubmit. | Ensure SSN is 9 digits without dashes. |
INVALID_PHONE_FORMAT | The phone number format is invalid. | Use a valid phone number format. |
INVALID_ADDRESS | The address is invalid. | Verify all address fields are complete and valid. |
INVALID_RELATIONSHIP_TYPE | The relationship type is invalid. | Use a valid relationship type enum value. |
INVALID_STATE_CODE | The state code is invalid. | Use a valid 2-letter state code. |
INVALID_ZIPCODE | The zipcode is invalid. | Use a valid 5-digit or 9-digit zipcode. |
DUPLICATE_SSN | Policy holder and dependents must have unique SSNs. | Ensure each enrollee has a unique SSN. |
INVALID_HIOS_ID | The specified hios_id is not valid for ICHRA enrollments. | Verify the hios_id and ensure the plan is available. |
Member/Contract Lookup Errors
These errors indicate problems finding or matching member records.
| Error Code | Message | Resolution |
|---|---|---|
MEMBER_NOT_FOUND | Could not match the member to an existing record. | Verify the member information (name, DOB, SSN) is correct. |
CONTRACT_NOT_FOUND | No coverage found for this member. | Verify the oscar_id and coverage dates are correct. |
POLICY_NOT_FOUND | Unable to determine the policy for this enrollment. | Verify the hios_id and plan_year are correct. |
DEPENDENT_NOT_FOUND | The dependent was not found. | Verify the dependent information is correct. |
MEMBER_NOT_ON_CONTRACT | The specified member is not part of this coverage. | Verify the member is enrolled on the specified contract. |
OSCAR_ID_MISMATCH | The Oscar ID does not match the expected value. | Verify the oscar_id format (OSCXXXXXXXX-XX). |
MULTIPLE_MEMBERS_FOUND | Multiple members found matching the provided information. | Contact Oscar support to resolve the duplicate. |
Date/Coverage Period Errors
These errors indicate problems with dates or coverage periods.
| Error Code | Message | Resolution |
|---|---|---|
DATE_OUTSIDE_CONTRACT_PERIOD | The date is outside the contract coverage period. | Ensure dates fall within the member's coverage period. |
COVERAGE_START_DATE_INVALID | The coverage start date cannot be after the coverage end date. | Verify coverage_start_date is before coverage_end_date. |
COVERAGE_END_DATE_INVALID | The coverage end date is invalid. | Verify the coverage end date is valid. |
PREMIUM_DATES_OUTSIDE_COVERAGE | Premium dates are outside the coverage period. | Ensure premium dates align with coverage dates. |
EFFECTIVE_DATE_IN_PAST | The effective date is in the past. | Use a current or future effective date. |
COVERAGE_DATES_OVERLAP | Coverage dates overlap with existing coverage. | Adjust dates to avoid overlap. |
INVALID_PLAN_YEAR | The plan year is invalid. | Use a valid plan year (e.g., "2025"). |
EVENT_DATE_OUTSIDE_QLE_WINDOW | The event date is outside the qualifying life event window. | Verify the QLE date is within the allowed window. |
MISSING_QUALIFYING_EVENT | A qualifying life event is required to change this policy outside of Open Enrollment. | Include a qle_info block with the event type and date. |
INVALID_COVERAGE_START_DATE_FOR_QLE | The coverage start date is not valid for the provided qualifying life event. The message lists the valid coverage start dates. | Set the coverage start date to one of the valid dates listed in the message. |
QLE_HAS_NO_VALID_COVERAGE_DATES | The provided qualifying life event has no valid coverage effective dates (e.g., the QLE is not valid in the state, or the application/QLE date is outside the enrollment window). | Verify the QLE type and that the QLE and application dates fall within the special enrollment period. |
Financial/Premium Errors
These errors indicate problems with premium or financial data.
| Error Code | Message | Resolution |
|---|---|---|
INVALID_PREMIUM_AMOUNT | The premium amount is invalid. | Verify the premium amount format and value. |
PREMIUM_AMOUNT_MISMATCH | The premium amount does not match expected value. | Verify the total_premium matches the plan's premium. |
MISSING_PREMIUM_DATA | Required premium data is missing. | Include all required premium fields. |
PREMIUM_OUT_OF_RANGE | The premium amount is outside the valid range. | Verify the premium amount is reasonable. |
Relationship/Dependent Errors
These errors indicate problems with enrollee relationships or dependent eligibility.
| Error Code | Message | Resolution |
|---|---|---|
INVALID_DEPENDENT_RELATIONSHIP | The dependent relationship type is invalid. | Use a valid relationship_type enum value. |
DEPENDENT_AGE_LIMIT_EXCEEDED | The dependent has exceeded the age limit for coverage. | Dependents must be under 26 years old. |
DUPLICATE_DEPENDENT | A duplicate dependent was found. | Remove duplicate enrollees from the request. |
POLICY_HOLDER_REQUIRED | A policy holder is required in the enrollment request. | Include an enrollee with relationship_type "POLICY_HOLDER". |
MULTIPLE_SPOUSES_NOT_ALLOWED | Only one spouse is allowed per policy. | Include only one enrollee with relationship_type "SPOUSE". |
POLICY_HOLDER_TOO_YOUNG | The policy holder does not meet age requirements. | Policy holder must be at least 18 years old. |
Address/Service Area Errors
These errors indicate problems with address validation or service area eligibility.
| Error Code | Message | Resolution |
|---|---|---|
ADDRESS_NOT_IN_SERVICE_AREA | The member's address is not in the service area for this policy. | Verify the address is in Oscar's service area for the selected plan. |
ADDRESS_NOT_IN_RATING_AREA | The member's address is not in a valid rating area for this policy. | Verify the address matches the plan's rating area. |
ADDRESS_VERIFICATION_FAILED | Unable to verify the address. An exact match was not found. | Verify the address is complete and correctly formatted. |
Transient Errors - RETRY
These errors are temporary and should be retried with exponential backoff.
| Error Code | Message | Resolution |
|---|---|---|
SERVICE_TEMPORARILY_UNAVAILABLE | The service is temporarily unavailable. Please try again. | Retry the request after a short delay. |
REQUEST_TIMEOUT | The request timed out. Please try again. | Retry the request after a short delay. |
UPSTREAM_SERVICE_ERROR | An upstream service error occurred. | Retry the request after a short delay. |
Internal Errors - ESCALATE
These errors require Oscar intervention. Contact Oscar support with the application_id.
| Error Code | Message | Resolution |
|---|---|---|
INTERNAL_PROCESSING_ERROR | An internal error occurred. Please contact Oscar support. | Contact Oscar support with the application_id. |
ELIGIBILITY_CONFLICT | An eligibility conflict was detected. Please contact Oscar support. | Contact Oscar support to resolve the conflict. |
DATA_INTEGRITY_ERROR | A data integrity error occurred. | Contact Oscar support with the application_id. |
PERMISSION_DENIED | Permission denied. Please contact Oscar support. | Contact Oscar support to verify permissions. |
Example Error Responses
Validation Error (400)
{
"application_id": null,
"enrollees": [],
"message": "The request could not be processed due to validation errors.",
"errors": [
{
"error_code": "INVALID_SSN_FORMAT",
"message": "The SSN provided is invalid. Please verify and resubmit."
},
{
"error_code": "INVALID_DATE_FORMAT",
"message": "The date format is invalid."
}
]
}Member Not Found (400)
{
"application_id": "abc123def456789012345678abcdef12",
"enrollees": [],
"message": "The request could not be processed due to validation errors.",
"errors": [
{
"error_code": "MEMBER_NOT_FOUND",
"message": "Could not match the member to an existing record."
}
]
}Service Unavailable (503)
{
"application_id": null,
"enrollees": [],
"message": "The service is temporarily unavailable. Please retry.",
"errors": [
{
"error_code": "SERVICE_TEMPORARILY_UNAVAILABLE",
"message": "There are pending transactions for this member. Please try again later."
}
]
}Internal Error (500)
{
"application_id": "def456abc789012345678901fedcba98",
"enrollees": [],
"message": "An error occurred processing your request.",
"errors": [
{
"error_code": "ELIGIBILITY_CONFLICT",
"message": "An eligibility conflict was detected. Please contact Oscar support."
}
]
}Handling Errors in Code
Python Example
import requests
def update_membership(request_data):
response = requests.post(
"https://ichra-api.hioscar.com:444/ichra-api/v1/memberships/update-membership",
json=request_data,
cert=("client.crt", "client.key"),
)
if response.status_code == 200:
return response.json()
error_response = response.json()
# Handle by category
if response.status_code == 400:
# ACTIONABLE: Fix the request
for error in error_response.get("errors", []):
print(f"Fix {error['error_code']}: {error['message']}")
raise ValueError("Request validation failed")
elif response.status_code == 503:
# RETRY: Transient error
raise RetryableError("Service temporarily unavailable")
elif response.status_code == 500:
# ESCALATE: Contact Oscar support
app_id = error_response.get("application_id")
raise InternalError(f"Contact Oscar support. Application ID: {app_id}")
else:
raise Exception(f"Unexpected error: {response.status_code}")JavaScript Example
async function updateMembership(requestData) {
const response = await fetch(
'https://ichra-api.hioscar.com:444/ichra-api/v1/memberships/update-membership',
{
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(requestData),
},
);
const data = await response.json();
if (response.ok) {
return data;
}
// Handle by status code
switch (response.status) {
case 400:
// ACTIONABLE: Log errors for fixing
data.errors.forEach((error) => {
console.error(`${error.error_code}: ${error.message}`);
});
throw new ValidationError(data.errors);
case 503:
// RETRY: Throw retryable error
throw new RetryableError(data.message);
case 500:
// ESCALATE: Log application_id for support
console.error(`Contact Oscar support. Application ID: ${data.application_id}`);
throw new InternalError(data.message);
default:
throw new Error(`Unexpected error: ${response.status}`);
}
}Support
If you encounter an ESCALATE error or need assistance:
- Collect the
application_idfrom the error response - Note the
error_codeand error message - Contact Oscar support with this information
For questions about this API, contact the ICHRA team via Slack at #ichra-tech.
Changelog
| Date | Changes |
|---|---|
| 2026-07-15 | Added QLE_HAS_NO_VALID_COVERAGE_DATES and ADDRESS_NOT_IN_SERVICE_AREA (rating-area case), both actionable, for errors that previously surfaced as INTERNAL_PROCESSING_ERROR. |
| 2026-07-15 | Added INVALID_COVERAGE_START_DATE_FOR_QLE (actionable) for QLE coverage-start-date mismatches that previously surfaced as INTERNAL_PROCESSING_ERROR. Documented MISSING_QUALIFYING_EVENT. |
| 2026-02-04 | Initial release of error handling documentation with error codes, categories, and retry strategies. |
Updated about 1 month ago
