🚀 Simplify your work by integrating Haufe Copilot via API
Guides

Error Handling

Error response structure, HTTP error codes, rate limit headers, and streaming errors.

This guide covers error handling for Copilot via API.

Response Structure

All error responses share a consistent JSON structure:

{
    "error_code": "<string>",
    "detail": "<string>"
}
  • error_code — a stable string identifier for the error type. Use this in your error handling logic.
  • detail — a human-readable description. Treat this as informational; do not rely on it programmatically.

This structure is returned for all errors, including unexpected ones. If an unhandled error occurs, the API returns HTTP 500 with a generic error_code and detail rather than exposing internal details.

Gateway Errors

The API gateway rejects a request before it reaches the API when the credentials are missing or invalid. These responses have a different structure:

{
    "message": "Unauthorized",
    "http_status_code": 401
}
HTTP StatusMeaningCause
401UnauthorizedThe request has no api-key or Authorization header, the API key is unknown, the access token is expired, revoked, or not valid, or the OAuth client has no active subscription.

See Authentication for the header of each authentication method.

HTTP Errors

The table below lists the possible HTTP status codes, their meanings, and example response bodies.

HTTP StatusMeaningResponse
400Bad Request - Content Filter{"error_code": "content_filter_violation", "detail": "The request was rejected due to a content filter violation."}
400Request Metadata Missing{"error_code": "request_metadata_missing_or_incomplete", "detail": "Request lacks required request metadata"}
401Unauthorized{"error_code": "unauthorized", "detail": "Missing or invalid API key"}
403Assistant Not Licensed{"error_code": "assistant_not_licensed", "detail": "The access token has no licensed product for this assistant"}
403Thread Requires Access Token{"error_code": "thread_requires_access_token", "detail": "The thread was created with an access token. Send an access token to run it"}
413Thread Too Long{"error_code": "thread_capacity_exceeded", "detail": "Thread context window capacity has been exceeded"}
422User ID Conflicts With Token{"error_code": "user_id_conflicts_with_token", "detail": "Do not send a user_id with an access token. The token gives the user"}
422User Tenant ID Conflicts With Token{"error_code": "user_tenant_id_conflicts_with_token", "detail": "Do not send a user_tenant_id with an access token. The token gives the tenant"}
422User Tenant ID Without User ID{"error_code": "user_tenant_id_without_user_id", "detail": "Send a user_id with the user_tenant_id. A space belongs to a user and a tenant"}
500Internal Server Error{"error_code": "internal_server_error", "detail": "Internal Server Error"}
500Attachment Not Stored{"error_code": "attachment_persistence_mismatch", "detail": "The attachment could not be stored due to an internal error."}
502LLM Provider Error{"error_code": "llm_provider_error", "detail": "The LLM provider encountered an error. Please try again later."}

llm_provider_error covers all failures of the language model backend, for example timeouts, connection errors or rate limits of the provider. Retry the request later. thread_capacity_exceeded means that the thread is too long for the context window of the model. Start a new thread.

The API itself sends the errors request_metadata_missing_or_incomplete, assistant_not_licensed, thread_requires_access_token, user_id_conflicts_with_token, user_tenant_id_conflicts_with_token and user_tenant_id_without_user_id. For their causes, see Request Metadata Validation, the OAuth guide and the Deep Agent guide.

Example

{
    "error_code": "content_filter_violation",
    "detail": "The request was rejected due to a content filter violation."
}

Rate Limit Errors (HTTP 429)

When you exceed a rate limit, the API returns HTTP 429 with the following body:

{
    "detail": "Rate Limit Exceeded"
}

The response also includes headers to help you implement retry logic:

Limit BreachedHeaderValue
Per-secondRetry-After-MillisecondsMilliseconds until the current second window resets
Per-secondX-Rate-Limit-SecondYour allowed requests-per-second limit
Per-minuteRetry-After-SecondsSeconds until the current minute window resets
Per-minuteX-Rate-Limit-MinuteYour allowed requests-per-minute limit

Use the Retry-After-Milliseconds or Retry-After-Seconds header value to wait before retrying. Implement exponential backoff for repeated 429 responses.

For the applicable rate limits, see the Rate Limits guide.

Errors During Streaming

When an error occurs during a streaming response, the stream will include all chunks generated up to the point of the error, followed by a final chunk containing the error details and finish reason in the meta_data field.

Example

{
    "message_id": "00000000-0000-0000-0000-000000000001",
    "thread_id": "00000000-0000-0000-0000-000000000001",
    "created_at": "2024-11-15T17:43:37.443794",
    "delta": {
        "role": "assistant",
        "content": "Die",
        "sources": [],
        "meta_data": null
    }
}
{
    "message_id": "00000000-0000-0000-0000-000000000001",
    "thread_id": "00000000-0000-0000-0000-000000000001",
    "created_at": "2024-11-15T17:43:37.446459",
    "delta": {
        "role": "assistant",
        "content": "",
        "sources": [],
        "meta_data": {
            "type": "common_metadata",
            "finish_reason": "content_filter_violation",
            "detail": "The request was rejected due to a content filter violation."
        }
    }
}

finish_reason is one of content_filter_violation, context_window_exceeded, llm_provider_error or internal_server_error.

warning

If an error occurs during streaming, the message is not persisted — even if you already received a message_id in the stream.

Next Steps

On this page