Skip to main content

Error Codes

All AudienceGPT API endpoints return errors in a consistent JSON format. This page documents the standard error envelope, HTTP status codes used across the API, and common error scenarios with troubleshooting guidance.

Standard Error Format

Every error response follows this structure:

{
"error": "Human-readable error message"
}
FieldTypeDescription
errorstringA human-readable description of what went wrong

Some endpoints include additional context fields alongside the error message:

{
"error": "Monthly classifications quota exceeded",
"limit": 10000,
"used": 10000,
"remaining": 0,
"resetsAt": "2026-03-01T00:00:00.000Z"
}

SDK endpoints always include CORS headers in error responses, so client-side JavaScript can read the error message.


HTTP Status Codes

400 Bad Request

The request body or query parameters are invalid, missing required fields, or violate constraints.

Error MessageEndpointCause
"messages array is required"/api/classifyMissing messages field in request body
"Too many messages (max 50)"/api/classifyMessage array exceeds 50 items
"topic_name is required"/api/topics (POST)Missing topic name when creating a topic
"ids array is required"/api/topics (DELETE)Missing IDs for bulk delete
"ids array is required"/api/topics/reclassifyMissing IDs for bulk reclassify
"Maximum 500 topics for local reclassify"/api/topics/reclassifyToo many IDs for local reclassify
"Maximum 100 topics for LLM reclassify"/api/topics/reclassifyToo many IDs for AI-powered reclassify
"filename, totalRows, and mappings are required"/api/import (POST)Missing required import batch fields
"Total rows exceeds maximum of 50000"/api/import (POST)Import file too large
"file object is required"/api/analyze-briefMissing file in brief upload
"Unsupported file type"/api/analyze-briefFile MIME type not in accepted list
"File too large (max 10 MB)"/api/analyze-briefFile exceeds 10 MB size limit
"At least 2 dimensions are required"/api/topics/generate-matrixNeed minimum 2 dimensions for matrix
"Too many combinations (N). Maximum is 5000."/api/topics/generate-matrixCartesian product exceeds 5,000
"Dimension \"?\" must have a name and at least one value"/api/topics/generate-matrixEmpty dimension name or values
"topicIds array or filters object required"/api/topics/catalog (POST)Missing both topicIds and filters
"activationIds array is required"/api/activations/bulk-*Missing activation IDs for bulk operation
"name, platform, and direction are required"/api/connections (POST)Missing required connection fields
"Maximum 20 connections per organization"/api/connections (POST)Connection limit reached
"topic_name is required"/api/sdk/check-duplicateMissing topic name for duplicate check

401 Unauthorized

Authentication failed. The request has no valid credentials or the credentials are expired/revoked.

Error MessageCause
"Unauthorized"No Authorization header or Clerk session cookie
"Invalid API key"API key hash not found in database
"API key has been revoked"Key exists but revoked_at is set
"API key has expired"Key exists but expires_at is in the past
"Invalid or expired SDK key"SDK publishable key not found or revoked
"Insufficient scopes"API key lacks the required scope for this endpoint
tip

If you receive "Insufficient scopes", check which scope the endpoint requires (listed in each endpoint's documentation) and ensure your API key was created with that scope. You cannot add scopes to an existing key -- create a new one with the correct scopes.

403 Forbidden

Authentication succeeded, but the user lacks the required permission for this operation.

Error MessageCause
"Forbidden"Clerk session user lacks the required org permission
"Only organization owners can perform full exports"Non-owner attempting a full (all-fields) export
"Requires library:delete permission"User lacks permission for bulk topic deletion
"Requires activate permission"User lacks permission for activation operations

404 Not Found

The requested resource does not exist or does not belong to your organization.

Error MessageCause
"Topic not found"Topic ID does not exist or is not in your library
"Activation not found"Activation ID does not exist or is not in your org
"Connection not found"Connection ID does not exist or is not in your org
"Batch not found"Import batch ID does not exist or is not in your org
"Sync run not found"Sync run ID does not exist for this connection
"Mapping not found"No mapping found for the specified topic name

405 Method Not Allowed

The HTTP method is not supported for this endpoint.

Cause
Using GET on a POST-only endpoint, or vice versa
SDK endpoints return this with CORS headers for unsupported methods

409 Conflict

The operation conflicts with the current state of the resource.

Error MessageCause
"Activation is deactivated, cannot deactivate"Attempting to deactivate an already-deactivated activation
"Activation is deactivated, must be active to refresh"Attempting to refresh a deactivated activation
"Batch is not processing"Attempting to cancel a batch that is not in processing status
"Batch already cancelled"Attempting to cancel a batch that was already cancelled

429 Too Many Requests

A usage quota has been exceeded. See Rate Limits & Quotas for full details.

Error MessageCause
"Monthly classifications quota exceeded"Organization has used all classification credits for the month
"Monthly exports quota exceeded"Organization has used all export credits for the month

The response includes additional fields:

{
"error": "Monthly classifications quota exceeded",
"limit": 10000,
"used": 10000,
"remaining": 0,
"resetsAt": "2026-03-01T00:00:00.000Z"
}

500 Internal Server Error

An unexpected server error occurred. These are not caused by invalid input and typically indicate a transient issue or a bug.

Error MessageCause
"Classification failed"Anthropic API call failed during classification
"Failed to list topics"Database query error in topic listing
"Failed to create topic"Database insert error
"Failed to list catalog topics"Database query error in catalog browsing
"Failed to add topics to library"Database insert error during catalog adoption
"Failed to process chunk"Import chunk processing error
"Reclassification failed"Error during reclassify pipeline
"Export failed"Streaming export error
"Internal server error"Generic catch-all for unexpected errors
warning

If you encounter persistent 500 errors, check the AudienceGPT status page or contact support. Transient 500 errors can usually be resolved by retrying the request after a short delay.

502 Bad Gateway

An external platform API returned an error during an activation or connection operation.

Error MessageCause
"Platform deactivation failed"DSP platform rejected the deactivation request
"Failed to deactivate old segment on platform"Platform error during refresh (step 1)
"Failed to create new segment on platform"Platform error during refresh (step 3)
"Connection test failed"External platform unreachable or rejected credentials

Common Scenarios

"Invalid API key" after key creation

API keys are hashed before storage. You receive the plaintext key only once at creation time. If you lose it, you must create a new key.

Resolution: Create a new API key via POST /api/keys and store the returned plaintext value securely.

"Insufficient scopes" on a previously working key

API key scopes are fixed at creation time. If an endpoint's required scope was recently added to the documentation, your existing key may not have it.

Resolution: Create a new API key with the required scope(s). Consider including all scopes you might need.

Import chunk returns { skipped: true }

This is not an error. The import pipeline tracks which chunks have been processed. If a chunk number has already been completed, the server returns { skipped: true } for idempotent retry safety.

Resolution: No action needed. Continue processing subsequent chunks.

"Batch is not processing" when cancelling

Import batches can only be cancelled while in processing status. If the batch has already completed, failed, or been cancelled, you will receive a 409.

Resolution: Check the batch status with GET /api/import/:batchId/status before attempting cancellation.

Activation refresh returns 502

A refresh involves 4 platform API calls (deactivate old, create new). If the external platform is temporarily unavailable, the refresh will fail.

Resolution: Retry after a few minutes. If the error persists, verify the connection credentials are still valid using POST /api/connections/:id/test.

Classification returns unexpected results

The classification pipeline uses Claude Sonnet 4.6 with web search. Unusual topics may produce unexpected classifications.

Resolution: Use POST /api/topics/:id/reclassify with { "llm": true } to re-run AI-powered classification. If the result is still incorrect, manually update the topic fields via PATCH /api/topics/:id.


Error Handling Best Practices

1. Always parse the error body

async function apiCall(url: string, options: RequestInit) {
const response = await fetch(url, options);

if (!response.ok) {
const body = await response.json().catch(() => ({}));
throw new ApiError(response.status, body.error || "Unknown error", body);
}

return response.json();
}

class ApiError extends Error {
constructor(
public status: number,
message: string,
public body: Record<string, unknown>
) {
super(message);
this.name = "ApiError";
}
}

2. Implement retry logic for transient errors

Retry on 500 and 502 errors with exponential backoff. Do not retry 400, 401, 403, or 409 errors -- these require corrective action.

const RETRYABLE_STATUSES = [500, 502, 503];

async function fetchWithRetry(
url: string,
options: RequestInit,
maxRetries = 3
) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await fetch(url, options);

if (RETRYABLE_STATUSES.includes(response.status) && attempt < maxRetries - 1) {
const delay = Math.pow(2, attempt) * 1000;
await new Promise((r) => setTimeout(r, delay));
continue;
}

return response;
} catch (networkError) {
if (attempt < maxRetries - 1) {
const delay = Math.pow(2, attempt) * 1000;
await new Promise((r) => setTimeout(r, delay));
continue;
}
throw networkError;
}
}

throw new Error("Max retries exceeded");
}

3. Handle quota errors gracefully

When you receive a 429, display the reset time to the user rather than retrying in a loop:

if (error.status === 429) {
const resetsAt = new Date(error.body.resetsAt);
console.log(`Quota exceeded. Resets at ${resetsAt.toLocaleDateString()}`);
}

4. Log error details for debugging

Include the HTTP status, error message, and request context in your logs:

catch (error) {
if (error instanceof ApiError) {
console.error(`[${error.status}] ${error.message}`, {
endpoint: url,
body: error.body,
});
}
}

Next Steps