============== Error Handling ============== All error responses use a consistent JSON format. This page documents the HTTP status codes, error body format, and common error scenarios for each module. .. contents:: On this page :local: :depth: 1 ---- Error Response Format --------------------- All errors return a JSON body with a ``detail`` field: .. code-block:: json { "detail": "Human-readable error message" } Some validation errors (HTTP 422) from Pydantic return a structured list of field-level errors: .. code-block:: json { "detail": [ { "loc": ["body", "email"], "msg": "value is not a valid email address", "type": "value_error.email" } ] } ---- HTTP Status Codes ----------------- .. list-table:: :header-rows: 1 :widths: 10 25 65 * - Code - Name - Description * - 200 - OK - Request succeeded. The response body contains the result. * - 201 - Created - Resource was successfully created. The response body contains the new resource ID. * - 302 - Found - Redirect to another URL (used by download endpoints). * - 400 - Bad Request - The request body or parameters are malformed. Check the ``detail`` message for specifics. * - 401 - Unauthorized - No valid authentication credentials provided. Either the session has expired or the API key is missing/invalid. * - 403 - Forbidden - The authenticated user does not have permission for this action. This can occur when accessing another user's resources or when the API key lacks the required scope. * - 404 - Not Found - The requested resource does not exist, or the authenticated user does not have access to it. For privacy, the server does not distinguish between "does not exist" and "no access." * - 409 - Conflict - The request conflicts with the current state. Common causes: report artifact not ready yet, duplicate resource name, or resource is still processing. * - 422 - Unprocessable Entity - Request body failed validation. The ``detail`` field contains the specific validation error. Common causes: missing required field, invalid enum value, empty project name, invalid model_type. * - 429 - Too Many Requests - Rate limit exceeded. Wait for the number of seconds indicated in the ``Retry-After`` header before retrying. * - 500 - Internal Server Error - An unexpected error occurred. The ``detail`` field may contain information about the failure. If this persists, check server logs. ---- Rate Limiting ------------- Rate-limited endpoints include the following headers in every response: .. list-table:: :header-rows: 1 :widths: 30 70 * - Header - Description * - ``X-RateLimit-Limit`` - Maximum number of requests allowed in the current window. * - ``X-RateLimit-Remaining`` - Number of requests remaining in the current window. * - ``X-RateLimit-Reset`` - Unix timestamp when the rate limit window resets. * - ``Retry-After`` - (Only on 429 responses) Seconds to wait before retrying. Rate-limited endpoints: - **Authentication** -- ``POST /api/auth/login``, ``POST /api/auth/register``, ``POST /api/auth/forgot-password`` - **Predictions** -- ``POST /api/mlops/deployments/{id}/predict``, ``POST /api/models/{id}/predict`` ---- Common Error Scenarios ---------------------- Authentication Errors ^^^^^^^^^^^^^^^^^^^^^ .. list-table:: :header-rows: 1 :widths: 10 30 60 * - Code - Error - Cause * - 401 - ``Missing or invalid credentials`` - No session cookie or API key, or the credentials have expired. * - 401 - ``Invalid email or password`` - Wrong password during login. * - 403 - ``Insufficient scope`` - API key does not have the required scope (e.g. ``predict`` scope missing for prediction endpoints). * - 409 - ``User already exists`` - Attempting to register with an email that is already taken. * - 422 - ``Password must be at least 8 characters`` - Password too short during registration or reset. * - 429 - ``Rate limit exceeded`` - Too many login/register attempts. Project Errors ^^^^^^^^^^^^^^ .. list-table:: :header-rows: 1 :widths: 10 30 60 * - Code - Error - Cause * - 404 - ``Project not found`` - Project ID does not exist or the user is not a member. * - 422 - ``Project name must not be empty`` - Name was blank or whitespace-only. Dataset Errors ^^^^^^^^^^^^^^ .. list-table:: :header-rows: 1 :widths: 10 30 60 * - Code - Error - Cause * - 404 - ``Dataset not found`` - Dataset ID does not exist or belongs to another project. * - 404 - ``Dataset version not found`` - No version exists for the given dataset. * - 422 - ``Unsupported file type`` - Uploaded file is not CSV or Parquet. Experiment Errors ^^^^^^^^^^^^^^^^^ .. list-table:: :header-rows: 1 :widths: 10 30 60 * - Code - Error - Cause * - 404 - ``Experiment not found`` - Experiment ID does not exist or is inaccessible. * - 422 - ``target_column not found in dataset`` - The specified target column does not exist in the dataset schema. * - 422 - ``Invalid problem_type`` - Must be ``classification`` or ``regression``. Model Errors ^^^^^^^^^^^^ .. list-table:: :header-rows: 1 :widths: 10 30 60 * - Code - Error - Cause * - 404 - ``Model not found`` - Model ID does not exist or is inaccessible. * - 500 - ``Prediction failed`` - H2O model failed to produce a prediction. Check input features match the training schema. Deployment Errors ^^^^^^^^^^^^^^^^^ .. list-table:: :header-rows: 1 :widths: 10 30 60 * - Code - Error - Cause * - 404 - ``Deployment not found or inactive`` - Deployment does not exist or has been deactivated. * - 422 - ``stage must be 'staging' or 'production'`` - Invalid stage value when creating a deployment. * - 422 - ``model_id must belong to project`` - The model is from a different project. * - 422 - ``to_stage must be 'production'`` - Invalid promote target. * - 422 - ``Provide to_deployment_id or to_model_id`` - Rollback request missing both identifiers. Report Errors ^^^^^^^^^^^^^ .. list-table:: :header-rows: 1 :widths: 10 30 60 * - Code - Error - Cause * - 409 - ``Report has no artifact yet (still processing)`` - Attempting to view or download a report that is still being generated. * - 422 - ``Invalid kind`` - Report kind must be one of: ``deployment``, ``experiment``, ``model``, ``project``, ``synthgen``. Privacy Suite Errors ^^^^^^^^^^^^^^^^^^^^ .. list-table:: :header-rows: 1 :widths: 10 30 60 * - Code - Error - Cause * - 404 - ``Session not found`` - Privacy session does not exist or is inaccessible. * - 404 - ``Anonymized output not found`` - Attempting to download before transformation is complete. * - 404 - ``Rule not found`` - Rule ID does not exist in the given policy. * - 422 - ``dataset_id or dataset_version_id is required`` - Session creation without specifying which dataset to scan. * - 422 - ``Dataset must belong to the same project as the policy`` - Cross-project dataset/policy mismatch. SynthGen Errors ^^^^^^^^^^^^^^^ .. list-table:: :header-rows: 1 :widths: 10 30 60 * - Code - Error - Cause * - 400 - ``Model is not ready`` - Attempting to generate from a model that is still training. * - 404 - ``Model not found`` - SynthGen model does not exist or is inaccessible. * - 409 - ``Job output not available yet`` - Attempting to download before generation completes. * - 422 - ``Invalid model_type`` - Model type must be one of: ``ctgan``, ``copulagan``, ``tvae``, ``gaussian_copula``. * - 422 - ``num_rows must be between 1 and N`` - Requested row count exceeds the streaming limit. Studio Errors ^^^^^^^^^^^^^ .. list-table:: :header-rows: 1 :widths: 10 30 60 * - Code - Error - Cause * - 404 - ``Deployment not found or inactive`` - The deployment linked to the session is no longer active. * - 500 - ``Baseline prediction failed`` - The baseline input caused a prediction error. Check that input features match the deployment's feature schema. * - 500 - ``Scenario prediction failed`` - A scenario's modified input caused a prediction error. ---- Retry Strategy -------------- For transient errors (429, 500, 502, 503, 504) the recommended retry strategy is exponential backoff: .. code-block:: python import time import requests def api_request(method, url, **kwargs): """Make an API request with exponential backoff retry.""" max_retries = 3 for attempt in range(max_retries + 1): resp = requests.request(method, url, **kwargs) if resp.status_code == 429: wait = int(resp.headers.get("Retry-After", 2 ** attempt)) time.sleep(wait) continue if resp.status_code >= 500 and attempt < max_retries: time.sleep(2 ** attempt) continue resp.raise_for_status() return resp.json() raise Exception(f"Request failed after {max_retries} retries") ---- .. seealso:: - :doc:`authentication` -- How to authenticate API requests. - :doc:`index` -- API overview and conventions.