Error Handling
Complete error hierarchy for FastPII Connect — API errors, Gateway errors, and error handling patterns for Python and TypeScript.
Error Handling
All FastPII Connect errors inherit from FastPIIError, making it easy to catch specific errors or handle all errors at once.
Error hierarchy
FastPIIError
├── AuthenticationError (401)
├── PermissionError (403)
│ ├── QuotaExceededError (403 + type=quota_exceeded)
│ └── PolicyViolationError (403 + type=policy_violation)
├── ValidationError (400, 422)
├── NotFoundError (404)
├── RateLimitError (429)
├── ServerError (5xx)
├── ConnectionError (network failures)
├── TimeoutError (request timeouts)
└── GatewayError (Gateway base)
├── PolicyBlockError (403)
├── PIIInspectionError (503)
└── ProviderUnavailableError (502)API errors
These errors are returned by the Connect API (https://api.fastpii.com):
| Error | Status | When | Key attributes |
|---|---|---|---|
AuthenticationError | 401 | Invalid or missing API key | message, request_id |
PermissionError | 403 | Insufficient permissions | message, error_type, request_id |
QuotaExceededError | 403 | Monthly quota exceeded | message, request_id |
PolicyViolationError | 403 | Request violates policy | message, request_id |
ValidationError | 400/422 | Invalid request parameters | message, status_code, request_id |
NotFoundError | 404 | Resource not found | message, request_id |
RateLimitError | 429 | Rate limit exceeded | message, retry_after, request_id |
ServerError | 500+ | Internal server error | message, status_code, request_id |
ConnectionError | None | Network failure (no response) | message |
TimeoutError | None | Request timeout (no response) | message |
QuotaExceededError vs PolicyViolationError
Both are PermissionError subclasses with status 403, but they have different error_type values:
QuotaExceededError:error_type="quota_exceeded"— your monthly API call quota has been reachedPolicyViolationError:error_type="policy_violation"— the request content violates your workspace policy
Gateway errors
These errors are specific to the Gateway (https://gateway.fastpii.com):
| Error | Status | When | Key attributes |
|---|---|---|---|
PolicyBlockError | 403 | Request blocked by workspace PII policy before reaching the LLM | message, request_id |
PIIInspectionError | 503 | LLM response blocked because PII was detected in the output | message, request_id |
ProviderUnavailableError | 502 | Upstream LLM provider unavailable or returned an error | message, request_id |
PolicyBlockError vs PIIInspectionError
PolicyBlockError: The request was blocked before being sent to the LLM. Your workspace policy detected PII in the input messages.PIIInspectionError: The response from the LLM was blocked. PII was detected in the model's output and the response was not returned to you.
Python error handling
from fastpii_connect.errors import (
FastPIIError,
AuthenticationError,
PermissionError,
QuotaExceededError,
PolicyViolationError,
ValidationError,
NotFoundError,
RateLimitError,
ServerError,
ConnectionError,
TimeoutError,
GatewayError,
PolicyBlockError,
PIIInspectionError,
ProviderUnavailableError,
)
# --- API errors ---
try:
result = client.detect("text")
except AuthenticationError as e:
print(f"Invalid API key: {e.message}")
except QuotaExceededError as e:
print(f"Quota exceeded: {e.message}")
except PolicyViolationError as e:
print(f"Policy violation: {e.message}")
except RateLimitError as e:
print(f"Rate limited. Retry after {e.retry_after} seconds")
except ValidationError as e:
print(f"Bad request: {e.message} (status {e.status_code})")
except ServerError as e:
print(f"Server error: {e.message} (status {e.status_code})")
except ConnectionError as e:
print(f"Network error: {e.message}")
except TimeoutError as e:
print(f"Timeout: {e.message}")
except FastPIIError as e:
print(f"FastPII error: {e.message}")
# --- Gateway errors ---
try:
response = client.gateway.chat.completions(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello!"}],
)
except PolicyBlockError as e:
print(f"Request blocked by PII policy: {e.message}")
except PIIInspectionError as e:
print(f"Response contained PII: {e.message}")
except ProviderUnavailableError as e:
print(f"LLM provider unavailable: {e.message}")
except GatewayError as e:
print(f"Gateway error: {e.message} (type={e.error_type})")Python error attributes
| Attribute | Type | Description |
|---|---|---|
message | str | Human-readable error message |
status_code | int or None | HTTP status code (None for network errors) |
error_type | str or None | Machine-readable error type |
request_id | str or None | Request ID for debugging (from X-Request-ID header) |
retry_after | int or None | Seconds to wait before retrying (RateLimitError only) |
TypeScript error handling
import {
FastPIIError,
AuthenticationError,
PermissionError,
QuotaExceededError,
PolicyViolationError,
ValidationError,
NotFoundError,
RateLimitError,
ServerError,
ConnectionError,
TimeoutError,
GatewayError,
PolicyBlockError,
PIIInspectionError,
ProviderUnavailableError,
} from "fastpii-connect";
// --- API errors ---
try {
const result = await client.detect("text");
} catch (error) {
if (error instanceof AuthenticationError) {
console.log(`Invalid API key: ${error.message}`);
} else if (error instanceof QuotaExceededError) {
console.log(`Quota exceeded: ${error.message}`);
} else if (error instanceof PolicyViolationError) {
console.log(`Policy violation: ${error.message}`);
} else if (error instanceof RateLimitError) {
console.log(`Rate limited. Retry after ${error.retryAfter} seconds`);
} else if (error instanceof ValidationError) {
console.log(`Bad request: ${error.message} (status ${error.statusCode})`);
} else if (error instanceof ServerError) {
console.log(`Server error: ${error.message} (status ${error.statusCode})`);
} else if (error instanceof ConnectionError) {
console.log(`Network error: ${error.message}`);
} else if (error instanceof TimeoutError) {
console.log(`Timeout: ${error.message}`);
} else if (error instanceof FastPIIError) {
console.log(`FastPII error: ${error.message}`);
}
}
// --- Gateway errors ---
try {
const response = await client.gateway.chat.completions({
model: "gpt-4o",
messages: [{ role: "user", content: "Hello!" }],
});
} catch (error) {
if (error instanceof PolicyBlockError) {
console.log(`Request blocked by PII policy: ${error.message}`);
} else if (error instanceof PIIInspectionError) {
console.log(`Response contained PII: ${error.message}`);
} else if (error instanceof ProviderUnavailableError) {
console.log(`LLM provider unavailable: ${error.message}`);
} else if (error instanceof GatewayError) {
console.log(`Gateway error: ${error.message} (type=${error.errorType})`);
}
}TypeScript error properties
| Property | Type | Description |
|---|---|---|
message | string | Human-readable error message (inherited from Error) |
statusCode | number | null | HTTP status code (null for network errors) |
errorType | string | null | Machine-readable error type |
requestId | string | null | Request ID for debugging (from X-Request-ID header) |
retryAfter | number | null | Seconds to wait before retrying (RateLimitError only) |
Automatic retries
Both the API client and Gateway client automatically retry on transient errors:
- Retryable status codes: 408, 429, 502, 503, 504
- Retryable methods: GET, HEAD, PUT, DELETE (POST is not retried by default)
- Retry count: Configurable via
max_retries(default: 2) - Backoff: Exponential with jitter —
0.5 * 2^attempt ± 25% jitter - Rate limit: On 429, the
Retry-Afterheader value is used as the backoff
# Python: increase retries
client = FastPIIClient(api_key="fpk_...", max_retries=4)// TypeScript: increase retries
const client = new FastPIIClient({ apiKey: "fpk_...", maxRetries: 4 });Streaming errors
When using Gateway streaming, errors can appear as events within the stream:
from fastpii_connect import ChatCompletionChunk, StreamDone, StreamError
from fastpii_connect.errors import PolicyBlockError, PIIInspectionError
for event in client.gateway.chat.stream(model="gpt-4o", messages=[...]):
if isinstance(event, StreamError):
# Stream errors are automatically raised as exceptions
# This code is unreachable unless you catch them
pass
elif isinstance(event, ChatCompletionChunk):
print(event.content, end="")
elif isinstance(event, StreamDone):
print("\n[Done]")Stream errors are automatically converted to their corresponding exception types (PolicyBlockError, PIIInspectionError, ProviderUnavailableError, or GatewayError). You catch them the same way as non-streaming errors.
Request IDs
Every request includes a unique X-Request-ID header (format: fpi_<16-hex-chars>). When contacting support, include the request_id from the error:
try:
result = client.detect("text")
except FastPIIError as e:
print(f"Error: {e.message}, Request ID: {e.request_id}")
# Include e.request_id in your support requesttry {
const result = await client.detect("text");
} catch (error) {
if (error instanceof FastPIIError) {
console.log(`Error: ${error.message}, Request ID: ${error.requestId}`);
// Include error.requestId in your support request
}
}