Skip to content

Errors

Every 4xx and 5xx response has the same shape, so your error handler only learns it once:

{
  "detail": {
    "code": "validation_error",
    "message": "Tool diameter must be > 0",
    "details": {"parameter": "tool_diameter", "value": -1},
    "request_id": "f8b8d6f0-2b18-4c5a-9b6e-..."
  }
}
  • code: stable snake_case identifier; safe to switch on.
  • message: English fallback.
  • details: endpoint-specific structured context.
  • request_id: quote in support tickets. Echoed in the X-Request-ID response header.

Error codes

Code Status Meaning
unauthorized 401 Missing / invalid / expired / revoked API key.
forbidden 403 Key lacks one of the route's required scopes (details.missing_scopes).
validation_error 400 Generic validation failure.
invalid_parameter 400 A specific parameter is out of range or unsupported.
missing_required_field 400 A required body field was omitted.
not_found 404 Resource does not exist for this user.
project_not_found 404 details.project_id.
equipment_not_found 404 details.equipment_id.
machine_not_found 404 details.product_id.
job_not_found 404 details.job_id.
tool_not_found 404 details.tool_id.
project_busy 400 A task is already running on this project (details.active_task_id).
task_cancelled 499 The task was cancelled cooperatively.
resource_ownership_error 403 The resource exists but is owned by a different user.
license_error 403 ModuleWorks licence problem.
storage_error 500 S3 / Mongo / Postgres failure.
moduleworks_error 500 ModuleWorks computation failed.
task_execution_error 500 Worker could not start the task.
database_error 500 Postgres failure.
internal_error 500 Catch-all.

Rate limit (429)

{
  "detail": {
    "code": "validation_error",
    "message": "Rate limit exceeded: 120 per minute",
    "details": {"retry_after_seconds": 30},
    "request_id": "..."
  }
}

Headers: Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.