Skip to content

Error Handling

Standard HTTP status codes are used to indicate success or failure.

Status Codes

CodeMeaningWhen
200SuccessText anonymization completed
202AcceptedFile upload accepted for processing
400Bad RequestMissing or invalid parameters
401UnauthorizedInvalid or missing bearer token
403ForbiddenEvaluation request limit (1,000) reached
404Not FoundJob ID does not exist or expired
422Unprocessable EntityRequest body validation failure
429Too Many RequestsEvaluation rate limit (30/min) exceeded
500Internal Server ErrorUnhandled server error

All error responses return JSON with a detail field.

Specific Errors

400 — Bad Request

json
{"detail": "text field is required"}
json
{"detail": "Unsupported file type. Supported types: pdf, docx, csv, excel"}
json
{"detail": "Uploaded file is empty"}

401 — Unauthorized

json
{"detail": "Bearer token missing"}
json
{"detail": "Invalid bearer token"}

Occurs when:

  • No Authorization: Bearer <token> header is provided
  • The token's signature is invalid, or the token has expired
  • An evaluation token has been revoked

403 — Evaluation Limit Reached

json
{"detail": "Evaluation request limit reached (1000). Contact techsupport@questa.solutions for a license."}

Returned when an evaluation token has used its 1,000 lifetime requests. The token will no longer process anonymization requests — contact techsupport@questa.solutions for a self-hosted license. Only the hosted demo's evaluation tokens are capped; self-hosted instances have no request limit.

404 — Not Found

json
{"detail": "Job not found"}

Occurs when:

  • The job_id does not exist
  • The job has expired (results retained for 1 hour)

422 — Validation Error

json
{
  "detail": [
    {
      "loc": ["body", "text"],
      "msg": "field required",
      "type": "value_error.missing"
    }
  ]
}

429 — Rate Limit

Evaluation tokens are limited to 30 requests per minute. Exceeding that returns 429 with a Retry-After header indicating how many seconds to wait:

json
{"detail": "Rate limit exceeded. Try again in 42 seconds."}

Back off and retry after Retry-After seconds. Only /anonymize/text and the file-upload endpoints count toward the rate limit. Self-hosted instances do not rate-limit.

500 — Internal Server Error

json
{"detail": "Internal server error"}

For file processing, errors during background processing are captured in the job's error field:

json
{
  "status": "failed",
  "progress": 50,
  "error": "Failed to extract text from PDF: file appears to be scanned/image-based",
  "created_at": 1678886400.0
}

Error Handling (Python)

python
import time

def anonymize_with_retry(client, payload, max_retries=3):
    for attempt in range(max_retries):
        try:
            response = client.post("/anonymize/text", json=payload)

            if response.status_code == 200:
                return response.json()

            if response.status_code == 401:
                raise PermissionError("Bearer token is missing or invalid")

            if response.status_code == 429:
                retry_after = int(response.headers.get("Retry-After", 5))
                time.sleep(retry_after)
                continue

            if response.status_code >= 500:
                time.sleep(2 ** attempt)
                continue

            response.raise_for_status()

        except requests.exceptions.RequestException as e:
            if attempt == max_retries - 1:
                raise
            time.sleep(2 ** attempt)

Error Handling (JavaScript)

javascript
async function anonymizeWithRetry(url, options, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const response = await fetch(url, options);

    if (response.ok) return response.json();

    if (response.status === 401) {
      throw new Error("Bearer token is missing or invalid");
    }

    if (response.status === 429) {
      const retryAfter = parseInt(response.headers.get("Retry-After") || "5");
      await new Promise((r) => setTimeout(r, retryAfter * 1000));
      continue;
    }

    if (response.status >= 500 && attempt < maxRetries - 1) {
      await new Promise((r) => setTimeout(r, 1000 * 2 ** attempt));
      continue;
    }

    throw new Error(`HTTP ${response.status}: ${await response.text()}`);
  }
}

Questa AI documentation.