Skip to main content

SDK errors

The SDK surfaces metadata for exceptions. All errors inherit from perceptron.errors.SDKError. Non-fatal semantic issues still land in PerceiveResult.errors; flip strict=True when you want them raised immediately during prompting and pointing.

Retrying safely

Wrap SDK calls with targeted exception handling so transient faults (rate limits, network blips) never crash your job while still surfacing actionable diagnostic info.

API error codes

API responses bubble up through the SDK as the error classes above. Use the table below to match symptoms (HTTP status, timeout, etc.) to the remediation you need in client code.
Symptom: 401 Unauthorized from API or SDK calls.Fix: Export PERCEPTRON_API_KEY (and PERCEPTRON_BASE_URL when self-hosting) or call configure(api_key="sk_live_..."). Share err.details.get("request_id") with support if the failure persists.
Symptom: Key is valid but lacks scope.Fix: Rotate/regenerate the key in the dashboard and ensure the organization has access to the requested provider (perceptron, fal, etc.).
Symptom: Too many requests per minute.Fix: Batch requests and implement exponential backoff using the surfaced retry_after seconds.
Symptom: Immediate BadRequestError, ExpectationError, or warnings in PerceiveResult.errors.Fix: Inspect err.details (provider message, offending field, request ID) or switch on strict=True to surface anchor issues early.
Symptom: Transient backend issue.Fix: Retry with jitter and log err.details.get("request_id") when opening support tickets.
Symptom: Long-running uploads or unstable network.Fix: Resize oversized images (<=1024px longest edge), prefer stream=True to receive incremental tokens, and reduce config(timeout=...) so hung connections fail fast.

Size and context limits

Oversized images (silent smart-resize)

Images with more than 6,144 patches (roughly anything above Full HD, image-area-wise) are smart-resized server-side before tokenization, preserving aspect ratio. The resize is not signaled in the response — usage.prompt_tokens reflects the post-resize count, not the original. How to detect: compute the native patch count client-side (⌈width/16⌉ × ⌈height/16⌉) and compare against 6,144. If your use case is sensitive to image quality (OCR on small text, fine spatial detection), pre-resize to the target resolution yourself before uploading.

Context overflow (400 Bad Request)

When the assembled prompt (text + image patches + reserved output tokens) exceeds Isaac 0.1’s 8K context window, the API returns a 400 with a descriptive message. There is no dedicated semantic error code today — clients should pattern-match the message string to detect this case specifically. Example response:
The same shape fires when input_tokens + max_new_tokens > context_length, with the message itemizing each term.

Decision trees with runnable repros

invalid_image (upload/source bytes)

  • Meaning: the SDK could not decode the bytes you pointed it at before the request ever left your machine.
  • Fix checklist:
    1. Make sure the path/bytes you pass into caption()/detect()/ocr() is a real bitmap (PNG/JPEG/WebP). When dealing with streams, flush the handle before re-reading it.
    2. Inspect err.details['origin'] to confirm which file triggered the failure and err.details['request_id'] (if the request made it to the API).
    3. If the asset lives on disk, open it with Pillow or Preview to confirm it is not truncated; if it is an HTTP URL, download it locally and retry.

anchor_missing / bounds_out_of_range (strict pointing)

  • Meaning: a box()/point()/polygon() tag is missing an explicit image= reference when multiple images exist, or the coordinates fall outside the detected width/height.
  • Fix checklist:
    1. When using @perceive(..., strict=True) always pass the image node into every tag: box(..., image=image_node). In single-image prompts, ensure the image appears before any tags.
    2. Use result.points_to_pixels(width, height) to sanity-check coordinate math before switching to strict mode.
    3. Log err.details['code'] (either anchor_missing or bounds_out_of_range) to branch your retry logic.