Errors and utilities

Retries

The client retries 408, 429 and 5xx responses, dropped connections and timeouts, with exponential backoff, and honors retry-after-ms and retry-after. It doesn't retry an error whose body says "retryable": false. Every retry of a document create or upload reuses the same Idempotency-Key, so it never starts or bills a second job.

RetryPolicy is a frozen dataclass:

FieldTypeDefaultDescription
max_retriesint2Retries after the first attempt. 0 disables retries.
backoff_initialfloat0.5First delay in seconds, doubled on each retry. 0 disables backoff.
backoff_maxfloat5.0Longest delay in seconds. 0 disables backoff.
backoff_jitterfloat0.25Fraction of each delay randomly taken off, from 0 to 1.
http_statusesset[int]{408, 429, 500, ..., 599}Statuses that are retried.
respect_retry_afterboolTrueWait what retry-after-ms or retry-after says instead of the backoff.
api_connection_errorboolTrueRetry NaceAPIConnectionError.
api_timeout_errorboolTrueRetry NaceAPITimeoutError.
exceptionsset[type[BaseException]]set()More exception types to retry.
predicateCallable[[BaseException], bool] | NoneNoneCalled with each error; True retries it too.
timeoutfloat | NoneNoneTotal budget in seconds for one call: every attempt plus the waits between them. None removes it.

The time budget

The default timeout=None disables the total retry budget. A slow retryable failure, including a timeout or a 529 after Drex's 55-second model deadline, can use the remaining retries. The default permits three attempts in total, so slow failures can take several minutes to surface, including waits.

An explicit timeout counts from the first attempt. Before each retry, the client adds the next wait to the time already spent; if that reaches the budget, it raises the last error. This check decides whether another attempt starts; it does not interrupt an attempt or enforce a hard deadline for the whole call.

The HTTP timeout is per HTTPX operation (connect, read, write and pool), rather than a wall-clock limit for an entire attempt.

from nace_sdk import NaceClient, RetryPolicy

# Opt into a retry budget; long failures may consume it before any retry.
client = NaceClient(retry=RetryPolicy(timeout=30.0))

Python honors server Retry-After delays without a maximum. With no retry budget, a long server delay can keep a call waiting much longer; configure RetryPolicy(timeout=...) if you need to limit when another attempt may start.

A policy for one call

A retry= on one call replaces the client's policy for that call. The client doesn't expose its policy, so build one from the policy you passed to the client, or from RetryPolicy():

import dataclasses

from nace_sdk import RetryPolicy

no_retries = dataclasses.replace(RetryPolicy(), max_retries=0)
job = client.documents.parse("https://example.com/report.pdf", retry=no_retries)

What else to know

  • An invalid policy raises NaceError: a negative max_retries, a negative or infinite delay, a jitter outside 0 to 1, or a nonpositive timeout.
  • Retried attempts carry an X-Nace-Retry-Count header.
  • Never retried: the job event stream, and a download cut off midway. See Progress events and Download a file.
  • Not retried unless you pass retry, since a retry after the first call landed would save something twice or fail: extraction_schemas.create and create_version (see Saved schemas), workspaces.create, workspaces.files.replace, and domains.create, publish and duplicate.

On this page