Errors¶
This page documents all HTTP error codes and error response formats returned by the Nodexa API.
Error Response Format¶
All errors return a JSON body with a consistent structure:
{
"error": {
"type": "authentication_error",
"code": "invalid_api_key",
"message": "The provided API key is invalid or has been revoked."
}
}
| Field | Type | Description |
|---|---|---|
error.type |
string |
Error category — see the type reference below |
error.code |
string |
Machine-readable error code for programmatic handling |
error.message |
string |
Human-readable description of the error |
HTTP Status Codes¶
400 Bad Request¶
The request is malformed or contains invalid parameters.
error.code |
Description |
|---|---|
invalid_request |
The request body is not valid JSON |
missing_required_field |
A required field (model, input) is absent |
invalid_model |
The model field is not a valid assistant UUID |
tool_not_supported_for_model |
The tool type is not compatible with the backing LLM model |
too_many_tools |
More than 128 tools were provided |
duplicate_tool_name |
Two or more tools in the request have the same name |
invalid_tool_name |
A tool name contains invalid characters or exceeds 64 chars |
invalid_input_type |
An item in the input array has an unrecognized type or role |
missing_call_id |
A function_call_output item is missing the call_id field |
Example:
{
"error": {
"type": "invalid_request_error",
"code": "too_many_tools",
"message": "You provided 150 tools. The maximum is 128 per request."
}
}
401 Unauthorized¶
Authentication failed. No API key was provided, or the key is not recognized.
error.code |
Description |
|---|---|
missing_api_key |
Neither x-api-key nor Authorization header was provided |
invalid_api_key |
The API key is malformed, expired, or has been revoked |
Example:
{
"error": {
"type": "authentication_error",
"code": "invalid_api_key",
"message": "The provided API key is invalid or has been revoked."
}
}
Checklist if you receive this error:
- Verify your API key starts with
nxk_ - Ensure you are using the correct header (
x-api-keyorAuthorization: Bearer) - Check that the key has not been revoked in the admin panel
- Verify you are targeting the correct Nodexa instance URL
403 Forbidden¶
The API key is valid but does not have permission to access this endpoint.
error.code |
Description |
|---|---|
insufficient_scope |
The key's scope does not include the required permission |
Example:
{
"error": {
"type": "authentication_error",
"code": "insufficient_scope",
"message": "This API key requires the 'user' scope to access memory endpoints."
}
}
Scope requirements:
| Endpoint | Required Scope |
|---|---|
POST /v1/responses |
assistant or full_access |
GET /user-claims/:userId |
user or full_access |
POST /user-claims |
user or full_access |
POST /user-claims/bulk |
user or full_access |
DELETE /user-claims/:userId/:claimKey |
user or full_access |
GET /v1/memory |
user or full_access |
DELETE /v1/memory |
user or full_access |
POST /v1/memory/opt-out |
user or full_access |
404 Not Found¶
The requested resource does not exist.
error.code |
Description |
|---|---|
assistant_not_found |
No assistant exists with the provided UUID |
claim_not_found |
No claim exists for the given userId + claimKey combination |
memory_item_not_found |
No memory item exists with the given ID |
response_not_found |
The previous_response_id does not match any stored response |
Example:
{
"error": {
"type": "not_found_error",
"code": "assistant_not_found",
"message": "No assistant found with ID 'asst_00000000-0000-0000-0000-000000000000'."
}
}
422 Unprocessable Entity¶
The request is syntactically valid but fails semantic validation.
error.code |
Description |
|---|---|
claim_value_too_large |
The claimValue exceeds the 64KB limit |
bulk_limit_exceeded |
More than 50 claims were provided in a bulk request |
503 Service Unavailable¶
The Nodexa platform or a downstream dependency is temporarily unavailable.
error.code |
Description |
|---|---|
upstream_unavailable |
The LLM provider is unreachable or returned a service error |
upstream_timeout |
The LLM provider did not respond within the timeout period |
service_overloaded |
The platform is under high load; retry after a brief pause |
Example:
{
"error": {
"type": "server_error",
"code": "upstream_timeout",
"message": "The LLM provider did not respond within the timeout period. Please try again."
}
}
Retry with exponential backoff
For 503 errors, implement retry logic with exponential backoff:
```js
async function callWithRetry(fn, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await fn();
} catch (err) {
if (err.status === 503 && attempt < maxRetries - 1) {
const delay = Math.pow(2, attempt) * 1000; // 1s, 2s, 4s
await new Promise(r => setTimeout(r, delay));
continue;
}
throw err;
}
}
}
```
Error Types Reference¶
error.type |
Meaning |
|---|---|
authentication_error |
Authentication or authorization failure |
invalid_request_error |
Malformed or invalid request parameters |
not_found_error |
The requested resource does not exist |
validation_error |
Request is valid JSON but fails semantic validation |
server_error |
Internal platform error or upstream provider failure |
Streaming Errors¶
When stream: true, errors that occur after the stream has started are delivered as response.error events rather than HTTP error status codes (since the HTTP response has already started with 200).
{
"type": "response.error",
"error": {
"type": "server_error",
"code": "upstream_timeout",
"message": "The LLM provider did not respond within the timeout period."
}
}
After a response.error event, the stream closes. Always listen for this event in your stream handler:
for await (const event of stream) {
if (event.type === 'response.error') {
console.error('Stream error:', event.error.message);
// Show error state in UI
break;
}
// ... handle other events
}
Error Handling Best Practices¶
Check status before reading output_text¶
const response = await client.responses.create({ model, input });
if (response.status === 'requires_action') {
// Handle tool calls — don't read output_text yet
} else if (response.status === 'completed') {
console.log(response.output_text);
}
Handle 401 centrally¶
async function callNodexa(requestFn) {
try {
return await requestFn();
} catch (err) {
if (err.status === 401) {
// API key invalid — log prominently, alert on-call
console.error('CRITICAL: Nodexa API key invalid or revoked');
throw err;
}
if (err.status === 503) {
// Transient — safe to retry
throw err;
}
throw err;
}
}