Error handling

This page shows you how to handle errors across the Jockey API: catch typed exceptions, retry transient failures, and poll for asynchronous status.

Error response format

When a request fails, the SDK raises a typed exception: ApiError in Python and TwelvelabsApiError in Node.js. The exception includes the HTTP status code and the parsed error body, which follows the same shape across the API:

1{
2 "code": "invalid_request",
3 "message": "The 'method' field is required",
4 "docs_url": "https://docs.twelvelabs.io/errors/invalid_request"
5}

Catch the exception and inspect its status code and body:

1from twelvelabs import TwelveLabs
2from twelvelabs.core.api_error import ApiError
3
4client = TwelveLabs(api_key="<YOUR_API_KEY>")
5
6try:
7 store = client.knowledge_stores.retrieve(knowledge_store_id="<YOUR_KNOWLEDGE_STORE_ID>")
8except ApiError as exc:
9 print(f"Status: {exc.status_code}")
10 print(f"Body: {exc.body}")

HTTP status codes

The status code is available on the exception (status_code in Python, statusCode in Node.js).

CodeMeaningAction
200SuccessProcess response
201CreatedResource created successfully
202AcceptedAsync operation started (knowledge store items)
400Bad RequestFix request parameters
401UnauthorizedCheck API key
403ForbiddenCheck permissions
404Not FoundCheck the resource identifier
429Rate LimitedBack off and retry
500Server ErrorRetry with backoff

Retry strategy

Retry on transient errors (429 rate limits and 5xx server errors). Do not retry client errors (400, 401, 403, 404). Fix the request instead.

1import time
2from twelvelabs import TwelveLabs
3from twelvelabs.core.api_error import ApiError
4
5client = TwelveLabs(api_key="<YOUR_API_KEY>")
6
7def with_retry(call, max_retries=3, base_delay=1):
8 """Call an SDK method with exponential backoff on 429 and 5xx errors."""
9 for attempt in range(max_retries):
10 try:
11 return call()
12 except ApiError as exc:
13 status = exc.status_code
14 if status == 429 or (status is not None and status >= 500):
15 delay = base_delay * (2 ** attempt)
16 print(f"Received {status}, retrying in {delay}s...")
17 time.sleep(delay)
18 continue
19 raise # Client errors are not retryable
20 raise RuntimeError("Exhausted retries")
21
22response = with_retry(lambda: client.responses.create(
23 knowledge_store_id="<YOUR_KNOWLEDGE_STORE_ID>",
24 input=[{"type": "message", "role": "user", "content": "<YOUR_PROMPT>"}],
25))

Common errors by endpoint

Assets

ErrorCauseFix
method requiredMissing upload methodAdd method: "direct" or method: "url"
File too largeDirect upload > 200MBUse URL upload method instead
Invalid URLURL not accessibleCheck URL is public and reachable

Knowledge stores

ErrorCauseFix
Invalid schemaBad JSON Schema in ingestion configurationValidate against JSON Schema draft 2020-12
Name requiredMissing name fieldAdd a name

Knowledge store items

ErrorCauseFix
Asset not foundInvalid asset_idCheck asset exists and is ready
Store not foundInvalid knowledge_store_idCheck the knowledge store identifier

Responses

ErrorCauseFix
Knowledge store requiredMissing knowledge_store_idAdd knowledge_store_id to the request
Invalid sessionBad session_idStart a new session (omit session_id)
Input requiredMissing input arrayAdd at least one message

Polling and async status

The platform processes content asynchronously. Any time you create an asset or add videos and images to a knowledge store, processing happens in the background. Poll the resource until it reaches the ready status before proceeding.

Polling helper

1import time
2
3def wait_for_ready(fetch, interval=5, timeout=600):
4 """Poll a resource until it is ready or failed.
5
6 `fetch` returns the current resource, for example:
7 lambda: client.assets.retrieve(asset_id=asset_id)
8 """
9 elapsed = 0
10 while elapsed < timeout:
11 resource = fetch()
12 if resource.status == "ready":
13 return resource
14 elif resource.status == "failed":
15 raise Exception(f"Resource failed: {resource.id}")
16 print(f" Status: {resource.status} ({elapsed}s elapsed)")
17 time.sleep(interval)
18 elapsed += interval
19 raise TimeoutError(f"Not ready after {timeout}s")

Usage

1# Wait for an asset
2asset = wait_for_ready(
3 lambda: client.assets.retrieve(asset_id="<YOUR_ASSET_ID>"), interval=5
4)
5
6# Wait for a knowledge store item (longer interval - indexing takes more time)
7item = wait_for_ready(
8 lambda: client.knowledge_store_items.retrieve(
9 knowledge_store_id="<YOUR_KNOWLEDGE_STORE_ID>", item_id="<YOUR_ITEM_ID>"
10 ),
11 interval=10,
12 timeout=600,
13)
ResourcePoll IntervalTypical WaitTimeout
Asset (direct)5s10-60s120s
Asset (URL)5s10-120s300s
Knowledge store item10s1-10 min600s

Batch polling

Wait for multiple resources in parallel:

1import concurrent.futures
2
3def wait_for_items(client, store_id, item_ids):
4 """Wait for multiple knowledge store items in parallel."""
5 def wait_one(item_id):
6 return wait_for_ready(
7 lambda: client.knowledge_store_items.retrieve(
8 knowledge_store_id=store_id, item_id=item_id
9 ),
10 interval=10,
11 )
12
13 with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
14 futures = {executor.submit(wait_one, iid): iid for iid in item_ids}
15 return {futures[f]: f.result() for f in concurrent.futures.as_completed(futures)}

Polling pitfalls

  • Don’t poll too aggressively: 1-second intervals waste rate limit budget
  • Always handle failed: failed resources don’t recover
  • Set a timeout: don’t poll forever if something goes wrong
  • Rely on polling: webhooks are not available during the research preview

Jupyter notebook

Open In Colab