Error Codes Reference
This document provides a comprehensive list of error codes returned by BioMCP APIs, their meanings, and recommended actions.
HTTP Status Codes
Success Codes (2xx)
Code |
Status |
Description |
200 |
OK |
Request successful |
201 |
Created |
Resource created successfully |
204 |
No Content |
Request successful, no content to return |
Client Error Codes (4xx)
Code |
Status |
Description |
Action |
400 |
Bad Request |
Invalid request parameters |
Check parameter format and values |
401 |
Unauthorized |
Missing or invalid API key |
Verify API key is correct |
403 |
Forbidden |
Access denied to resource |
Check permissions for API key |
404 |
Not Found |
Resource not found |
Verify ID exists and is correct format |
409 |
Conflict |
Resource conflict |
Check for duplicate requests |
422 |
Unprocessable Entity |
Validation error |
Review validation errors in response |
429 |
Too Many Requests |
Rate limit exceeded |
Implement backoff and retry |
Server Error Codes (5xx)
Code |
Status |
Description |
Action |
500 |
Internal Server Error |
Server error |
Retry with exponential backoff |
502 |
Bad Gateway |
Upstream service error |
Wait and retry |
503 |
Service Unavailable |
Service temporarily unavailable |
Check service status, retry later |
504 |
Gateway Timeout |
Request timeout |
Retry with smaller request |
BioMCP-Specific Error Codes
Article Errors (1xxx)
Code |
Error |
Description |
Example |
1001 |
INVALID_PMID |
Invalid PubMed ID format |
"abc123" instead of "12345678" |
1002 |
ARTICLE_NOT_FOUND |
Article does not exist |
PMID not in PubMed |
1003 |
DOI_NOT_FOUND |
DOI cannot be resolved |
Invalid or non-existent DOI |
1004 |
PUBTATOR_ERROR |
PubTator3 annotation failed |
Service temporarily down |
1005 |
PREPRINT_NOT_INDEXED |
Preprint not yet indexed |
Recently submitted preprint |
Trial Errors (2xxx)
Code |
Error |
Description |
Example |
2001 |
INVALID_NCT_ID |
Invalid NCT ID format |
Missing "NCT" prefix |
2002 |
TRIAL_NOT_FOUND |
Trial does not exist |
NCT ID not registered |
2003 |
INVALID_LOCATION |
Invalid geographic coordinates |
Latitude > 90 |
2004 |
NCI_API_REQUIRED |
NCI API key required |
Using NCI source without key |
2005 |
INVALID_STATUS |
Invalid trial status |
Status not recognized |
Variant Errors (3xxx)
Code |
Error |
Description |
Example |
3001 |
INVALID_HGVS |
Invalid HGVS notation |
Malformed HGVS string |
3002 |
VARIANT_NOT_FOUND |
Variant not in database |
Novel variant |
3003 |
INVALID_ASSEMBLY |
Invalid genome assembly |
Not hg19 or hg38 |
3004 |
COORDINATE_MISMATCH |
Coordinates don't match reference |
Position out of range |
3005 |
ALPHAGENOME_REQUIRED |
AlphaGenome API key required |
Prediction without key |
Gene/Drug/Disease Errors (4xxx)
Code |
Error |
Description |
Example |
4001 |
GENE_NOT_FOUND |
Gene symbol not recognized |
Non-standard symbol |
4002 |
DRUG_NOT_FOUND |
Drug/chemical not found |
Misspelled drug name |
4003 |
DISEASE_NOT_FOUND |
Disease term not recognized |
Non-standard terminology |
4004 |
SPECIES_NOT_SUPPORTED |
Only human genes supported |
Requesting mouse gene |
4005 |
AMBIGUOUS_QUERY |
Multiple matches found |
Common drug name |
Authentication Errors (5xxx)
Code |
Error |
Description |
Action |
5001 |
API_KEY_INVALID |
API key format invalid |
Check key format |
5002 |
API_KEY_EXPIRED |
API key has expired |
Renew API key |
5003 |
API_KEY_REVOKED |
API key was revoked |
Contact support |
5004 |
INSUFFICIENT_PERMISSIONS |
API key lacks required permissions |
Upgrade API key |
5005 |
IP_NOT_ALLOWED |
IP address not whitelisted |
Add IP to whitelist |
Rate Limit Errors (6xxx)
Code |
Error |
Description |
Headers |
6001 |
RATE_LIMIT_EXCEEDED |
Too many requests |
X-RateLimit-Remaining: 0 |
6002 |
DAILY_LIMIT_EXCEEDED |
Daily quota exceeded |
X-RateLimit-Reset: timestamp |
6003 |
CONCURRENT_LIMIT |
Too many concurrent requests |
X-Concurrent-Limit: 10 |
6004 |
BURST_LIMIT_EXCEEDED |
Short-term rate limit |
Retry-After: 60 |
Validation Errors (7xxx)
Code |
Error |
Description |
Example |
7001 |
MISSING_REQUIRED_FIELD |
Required parameter missing |
Missing gene for variant search |
7002 |
INVALID_FIELD_TYPE |
Wrong parameter type |
String instead of integer |
7003 |
VALUE_OUT_OF_RANGE |
Value outside allowed range |
Page number < 1 |
7004 |
INVALID_ENUM_VALUE |
Invalid enumeration value |
Phase "PHASE5" |
7005 |
MUTUALLY_EXCLUSIVE |
Conflicting parameters |
Both PMID and DOI provided |
External Service Errors (8xxx)
Code |
Error |
Description |
Service |
8001 |
PUBMED_UNAVAILABLE |
PubMed API down |
NCBI E-utilities |
8002 |
CLINICALTRIALS_UNAVAILABLE |
ClinicalTrials.gov down |
CT.gov API |
8003 |
BIOTHINGS_UNAVAILABLE |
BioThings API down |
MyGene/MyVariant |
8004 |
CBIOPORTAL_UNAVAILABLE |
cBioPortal unavailable |
cBioPortal API |
8005 |
EXTERNAL_TIMEOUT |
External service timeout |
Any external API |
Standard Error Response
{
"error": {
"code": 1002,
"type": "ARTICLE_NOT_FOUND",
"message": "Article with PMID 99999999 not found",
"details": {
"pmid": "99999999",
"searched_in": ["pubmed", "pmc", "preprints"]
}
},
"request_id": "req_abc123",
"timestamp": "2024-03-15T10:30:00Z"
}
Validation Error Response
{
"error": {
"code": 7001,
"type": "MISSING_REQUIRED_FIELD",
"message": "Validation failed",
"details": {
"errors": [
{
"field": "gene",
"message": "Gene symbol is required for variant search"
},
{
"field": "assembly",
"message": "Assembly must be 'hg19' or 'hg38'"
}
]
}
}
}
Rate Limit Error Response
{
"error": {
"code": 6001,
"type": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit of 180 requests per minute exceeded",
"details": {
"limit": 180,
"remaining": 0,
"reset": 1710504000,
"retry_after": 45
}
},
"headers": {
"X-RateLimit-Limit": "180",
"X-RateLimit-Remaining": "0",
"X-RateLimit-Reset": "1710504000",
"Retry-After": "45"
}
}
Error Handling Best Practices
1. Implement Exponential Backoff
import time
import random
def exponential_backoff(attempt: int, base_delay: float = 1.0):
"""Calculate exponential backoff with jitter."""
delay = base_delay * (2 ** attempt)
jitter = random.uniform(0, delay * 0.1)
return delay + jitter
# Usage
for attempt in range(5):
try:
response = await client.search(...)
break
except RateLimitError:
delay = exponential_backoff(attempt)
time.sleep(delay)
2. Handle Specific Error Types
try:
article = await client.articles.get(pmid)
except BioMCPError as e:
if e.code == 1002: # ARTICLE_NOT_FOUND
# Try alternative sources
article = await search_preprints(pmid)
elif e.code == 6001: # RATE_LIMIT_EXCEEDED
# Wait and retry
time.sleep(e.retry_after)
article = await client.articles.get(pmid)
else:
# Log and re-raise
logger.error(f"Unexpected error: {e}")
raise
3. Parse Error Details
def handle_validation_error(error_response):
"""Extract and handle validation errors."""
if error_response["error"]["type"] == "VALIDATION_ERROR":
for error in error_response["error"]["details"]["errors"]:
field = error["field"]
message = error["message"]
print(f"Validation error on {field}: {message}")
4. Monitor Rate Limits
class RateLimitMonitor:
def __init__(self):
self.limits = {}
def update_from_headers(self, headers):
"""Update rate limit state from response headers."""
self.limits["remaining"] = int(headers.get("X-RateLimit-Remaining", 0))
self.limits["reset"] = int(headers.get("X-RateLimit-Reset", 0))
if self.limits["remaining"] < 10:
logger.warning(f"Rate limit low: {self.limits['remaining']} remaining")
def should_delay(self):
"""Check if we should delay before next request."""
return self.limits.get("remaining", 100) < 5
Common Error Scenarios
Scenario 1: Gene Symbol Not Found
Error:
{
"error": {
"code": 4001,
"type": "GENE_NOT_FOUND",
"message": "Gene symbol 'HER2' not found. Did you mean 'ERBB2'?",
"details": {
"query": "HER2",
"suggestions": ["ERBB2", "ERBB2IP"]
}
}
}
Solution:
try:
gene = await client.genes.get("HER2")
except GeneNotFoundError as e:
if e.suggestions:
# Try first suggestion
gene = await client.genes.get(e.suggestions[0])
Scenario 2: Location Search Without Coordinates
Error:
{
"error": {
"code": 7001,
"type": "MISSING_REQUIRED_FIELD",
"message": "Latitude and longitude required for location search",
"details": {
"hint": "Use geocoding service to convert city names to coordinates"
}
}
}
Solution:
# Use a geocoding service first
coords = await geocode("Boston, MA")
trials = await client.trials.search(
conditions=["cancer"],
lat=coords.lat,
long=coords.long,
distance=50
)
Scenario 3: API Key Required
Error:
{
"error": {
"code": 2004,
"type": "NCI_API_REQUIRED",
"message": "NCI API key required for this operation",
"details": {
"get_key_url": "https://api.cancer.gov",
"feature": "biomarker_search"
}
}
}
Solution:
# Initialize client with API key
client = BioMCPClient(nci_api_key=os.getenv("NCI_API_KEY"))
# Or provide per-request
trials = await client.trials.search(
source="nci",
conditions=["melanoma"],
api_key="your-nci-key"
)
Debugging Tips
1. Enable Debug Logging
import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger("biomcp")
2. Inspect Raw Responses
# Enable raw response mode
client = BioMCPClient(debug=True)
# Access raw response
response = await client.articles.search(genes=["BRAF"])
print(response.raw_response)
3. Capture Request IDs
try:
result = await client.search(...)
except BioMCPError as e:
print(f"Request ID: {e.request_id}")
# Include request_id when reporting issues
Support
For error codes not listed here or persistent issues:
- Check FAQ for common issues
- Search GitHub Issues
- Report new issues with:
- Error code and message
- Request ID if available
- Minimal code to reproduce
- BioMCP version