Errors
NutrientAPI uses conventional HTTP status codes to indicate the success or failure of a request. Codes in the 2xx range indicate success, 4xx codes indicate a problem with the request, and 5xx codes indicate a server-side issue.
Error Response Format
All errors return a JSON object with an error key containing a machine-readable code and a human-readable message:
{
"error": {
"code": "validation_error",
"message": "ingredients must be a non-empty array"
}
}
The code field is a stable string identifier you can match against in your error handling logic. The message field is a description intended for developers; it may change over time and should not be parsed programmatically.
HTTP Status Codes
| Status | Error Code | Description |
|---|---|---|
400 |
bad_request |
The request body is not valid JSON or the Content-Type header is missing. |
401 |
unauthorized |
The Authorization header is missing or malformed. |
403 |
forbidden |
The API key is invalid, expired, or revoked. |
422 |
validation_error |
The request body is valid JSON but the content fails validation. See Validation Errors below. |
429 |
rate_limited |
You have exceeded the requests-per-second limit for your plan. See Rate Limits. |
503 |
service_unavailable |
The AI parsing service is temporarily unavailable. The request can be retried. See Handling 503 Errors below. |
Validation Errors (422)
A 422 Unprocessable Entity response means your JSON is syntactically valid but the data does not meet the API's requirements. These are the most common validation errors:
Missing or empty ingredients
// Request
{
"title": "My Recipe",
"ingredients": [],
"servings": 2
}
// Response (422)
{
"error": {
"code": "validation_error",
"message": "ingredients must be a non-empty array"
}
}
Invalid servings value
// Request
{
"title": "My Recipe",
"ingredients": ["1 cup rice"],
"servings": 0
}
// Response (422)
{
"error": {
"code": "validation_error",
"message": "servings must be a positive integer"
}
}
Non-string ingredient entries
// Request
{
"title": "My Recipe",
"ingredients": ["1 cup flour", 42, null],
"servings": 4
}
// Response (422)
{
"error": {
"code": "validation_error",
"message": "each ingredient must be a non-empty string"
}
}
Missing required fields
// Request (missing ingredients and servings)
{
"title": "My Recipe"
}
// Response (422)
{
"error": {
"code": "validation_error",
"message": "ingredients is required"
}
}
Handling 503 Errors
A 503 Service Unavailable response means the AI service used for ingredient parsing and food matching is temporarily unreachable. This is the only error that indicates a transient server-side issue worth retrying.
When the AI backend (used solely for natural language parsing) is unavailable, the API cannot process recipes. This is rare but can happen during upstream provider outages.
Recommended Retry Strategy
Use exponential backoff with jitter:
async function analyzeWithRetry(payload, maxRetries = 3) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const response = await fetch("https://api.nutrientapi.com/v1/analyze", {
method: "POST",
headers: {
"Authorization": `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});
if (response.status !== 503) {
return response;
}
if (attempt < maxRetries) {
// Exponential backoff: 1s, 2s, 4s + random jitter
const delay = Math.pow(2, attempt) * 1000;
const jitter = Math.random() * 500;
await new Promise(r => setTimeout(r, delay + jitter));
}
}
throw new Error("NutrientAPI unavailable after retries");
}
400, 401, 403, or 422 errors -- those indicate problems with your request that will not resolve on retry. Retrying 429 errors is acceptable but you should respect the rate limit window.
Quality Gate Rejections
Not all "errors" are HTTP errors. If the API processes your recipe but confidence scores fall below internal quality thresholds, it returns a 200 response with a quality_warnings field describing the issues. This is not an error -- you still get nutrient data -- but the warnings indicate that specific ingredients may be less accurate.
{
"ingredients": [ ... ],
"total_nutrients": { ... },
"quality_warnings": [
{
"ingredient": "a handful of mixed herbs",
"issue": "low_confidence_match",
"message": "Ingredient matched with low confidence; nutrients may be inaccurate"
}
]
}
You can use these warnings to flag specific ingredients in your UI or prompt users to clarify ambiguous descriptions.
Troubleshooting Guide
I am getting 401 but my key looks correct
- Verify the header is
Authorization: Bearer YOUR_KEYwith a space after "Bearer" - Check for trailing whitespace or newline characters in your key variable
- Ensure you are not URL-encoding the header value
I am getting 422 but my JSON looks valid
- Confirm
Content-Type: application/jsonis set - Check that
ingredientsis an array of strings, not a single string - Check that
servingsis a positive integer, not a string like"4" - Ensure none of the ingredient strings are empty (
"")
I am getting 503 errors frequently
- This is unusual. Check status.nutrientapi.com for ongoing incidents
- Implement the retry strategy described above
- If you cache results (which all plans allow), cached responses are unaffected by 503 errors
I am getting 429 but I am under my plan's monthly limit
- The
429status code applies to the per-second rate limit, not the monthly quota - Spread your requests over time rather than sending them in bursts
- See Rate Limits for the per-second limits on each plan
I am getting unexpected nutrient values
- This is not an error condition. Check the
ingredientsarray in the response to see which USDA foods were matched - Ambiguous ingredient descriptions (e.g., "oil" without specifying the type) may match unexpected foods
- Be as specific as possible: "extra virgin olive oil" will match better than "oil"
- Check
quality_warningsfor any low-confidence matches