Documentation Index Fetch the complete documentation index at: https://docs.emergence.ai/llms.txt
Use this file to discover all available pages before exploring further.
Error Codes
All CRAFT APIs return consistent error responses. This page documents the error format, all error codes, and troubleshooting guidance for each.
Error responses follow a standard JSON structure:
{
"error" : {
"code" : "RESOURCE_NOT_FOUND" ,
"message" : "Agent with ID '550e8400-e29b-41d4-a716-446655440000' not found." ,
"status" : 404 ,
"details" : {
"resource_type" : "artifact" ,
"resource_id" : "550e8400-e29b-41d4-a716-446655440000"
},
"request_id" : "req-a1b2c3d4-e5f6-7890-abcd-ef1234567890" ,
"trace_id" : "4bf92f3577b34da6a3ce929d0e0e4736"
}
}
Field Type Description codestring Machine-readable error code messagestring Human-readable error description statusinteger HTTP status code detailsobject Additional context (varies by error type) request_idstring Unique request identifier for support trace_idstring OpenTelemetry trace ID for end-to-end debugging
HTTP Status Codes
Status Meaning When Returned 400Bad Request Invalid request body, missing required fields, malformed parameters 401Unauthorized Missing, expired, or invalid JWT token 403Forbidden Valid token but insufficient permissions 404Not Found Resource does not exist or is not accessible 409Conflict Resource already exists or version conflict 422Unprocessable Entity Request is well-formed but semantically invalid 429Too Many Requests Rate limit exceeded 500Internal Server Error Unexpected server error 502Bad Gateway Upstream service (Keycloak, OpenFGA) unavailable 503Service Unavailable Service is starting up or shutting down
Error Codes Reference
The OpenAPI specifications define a base ErrorCode enum with 9 values: INVALID_REQUEST, INVALID_TOKEN, INSUFFICIENT_PERMISSIONS, RESOURCE_NOT_FOUND, RESOURCE_ALREADY_EXISTS, VALIDATION_ERROR, RATE_LIMIT_EXCEEDED, SERVICE_UNAVAILABLE, INTERNAL_ERROR. The implementation may return more specific codes within each category as documented below.
Authentication Errors (401)
Code Message Troubleshooting UNAUTHENTICATEDNo authentication token provided Include Authorization: Bearer <token> header TOKEN_EXPIREDAccess token has expired Refresh the token or obtain a new one TOKEN_INVALIDToken signature verification failed Ensure the token was issued by the correct Keycloak realm TOKEN_MALFORMEDToken format is invalid Check that the token is a valid JWT (three base64-encoded segments separated by dots)
Authorization Errors (403)
Code Message Troubleshooting FORBIDDENInsufficient permissions for this operation Check your role assignment on the target project; see RBAC Configuration PROJECT_ACCESS_DENIEDNo access to the specified project Verify the project ID in the request matches a project you have been granted access to ORG_ACCESS_DENIEDToken does not belong to this organization Authenticate against the correct Keycloak realm for the target organization
Resource Errors (404, 409)
Code Message Troubleshooting RESOURCE_NOT_FOUNDResource not found Verify the resource ID and ensure you have can_read permission RESOURCE_ALREADY_EXISTSResource with this identifier already exists Use a unique name or identifier; use PUT to update existing resources VERSION_CONFLICTResource has been modified by another request Re-fetch the resource and retry with the current version
Validation Errors (400, 422)
Code Message Troubleshooting VALIDATION_ERRORRequest body validation failed Check the details field for specific field-level errors INVALID_PARAMETERInvalid query parameter Verify parameter name, type, and allowed values MISSING_REQUIRED_FIELDRequired field is missing Include all required fields in the request body INVALID_FORMATField value format is invalid Check the expected format (UUID, URL, email, etc.) SEARCH_QUERY_INVALIDMalformed search query Use plain text for search queries; special operators are reserved
Rate Limiting Errors (429)
Code Message Troubleshooting RATE_LIMIT_EXCEEDEDRate limit exceeded Wait for the Retry-After header duration; implement exponential backoff QUOTA_EXCEEDEDTenant quota exceeded Contact your administrator to increase the quota for the exceeded dimension
Server Errors (500, 502, 503)
Code Message Troubleshooting INTERNAL_ERRORAn unexpected error occurred Retry the request; if persistent, report with request_id and trace_id UPSTREAM_UNAVAILABLEUpstream service is unavailable Keycloak or OpenFGA may be down; check service health. Governance down causes Assets/Utils to return 403 SERVICE_STARTINGService is initializing Wait for the service to complete startup; check readiness probe DATABASE_ERRORDatabase operation failed Retry the request; if persistent, check database connectivity
Handling Errors in Code
from em_runtime_assets_sdk import AssetsClient, ApiError
client = AssetsClient( base_url = "https://<host>:8002" , token = token)
try :
agent = await client.artifacts.get(artifact_uri)
except ApiError as e:
if e.status == 401 :
# Token expired -- refresh and retry
token = await refresh_token()
client.token = token
agent = await client.artifacts.get(artifact_uri)
elif e.status == 404 :
print ( f "Agent not found: { e.error.message } " )
elif e.status == 429 :
# Rate limited -- wait and retry
await asyncio.sleep(e.retry_after)
agent = await client.artifacts.get(artifact_uri)
else :
print ( f "Error { e.error.code } : { e.error.message } " )
print ( f "Request ID: { e.error.request_id } " )
raise
import { AssetsClient , ApiError } from '@emergence/em-runtime-assets-sdk' ;
const client = new AssetsClient ({
baseUrl: 'https://<host>:8002' ,
token: accessToken
});
try {
const agent = await client . agents . get ( agentId );
} catch ( error ) {
if ( error instanceof ApiError ) {
switch ( error . status ) {
case 401 :
// Refresh token and retry
break ;
case 404 :
console . log ( `Agent not found: ${ error . error . message } ` );
break ;
case 429 :
// Wait for retry-after and retry
await sleep ( error . retryAfter * 1000 );
break ;
default :
console . error ( `Error ${ error . error . code } : ${ error . error . message } ` );
console . error ( `Request ID: ${ error . error . requestId } ` );
}
}
}
# Check the HTTP status code
HTTP_STATUS = $( curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer $TOKEN " \
"https://<host>:8002/assets/artifacts/ $ARTIFACT_URI " )
if [ " $HTTP_STATUS " -eq 401 ]; then
echo "Token expired, refreshing..."
TOKEN = $( refresh_token )
elif [ " $HTTP_STATUS " -eq 404 ]; then
echo "Agent not found"
elif [ " $HTTP_STATUS " -eq 429 ]; then
echo "Rate limited, waiting..."
sleep 60
fi
Retry Strategy
For transient errors (429, 500, 502, 503), implement exponential backoff with jitter:
Attempt Wait Time Max Wait 1st retry 1 second + jitter 2 seconds 2nd retry 2 seconds + jitter 4 seconds 3rd retry 4 seconds + jitter 8 seconds 4th retry 8 seconds + jitter 16 seconds Max retries 5 30 seconds
For 429 errors, always respect the Retry-After header rather than using exponential backoff. The header provides the exact wait time until the rate limit window resets.
Getting Help
When reporting an issue, include:
The request_id from the error response
The trace_id for end-to-end correlation
The timestamp of the request
The full error response body
Next Steps
API Overview Review the full API structure and endpoints.
API Authentication Learn how to obtain and manage JWT tokens.
Python SDK Use the Python SDK with built-in error handling.
TypeScript SDK Use the TypeScript SDK with built-in error handling.