cocoindex-io/cocoindex · error · DeadlineExceededError
CocoIndex timeout deadline exceeded
Error message
CocoIndex timeout deadline exceeded
What it means
DeadlineExceededError is raised by retry_transient when the cooperative deadline has expired: no attempt may start past the deadline, and a remaining time of exactly zero or less counts as expired before each attempt. It can also arise with bound_attempt=True when asyncio.wait_for cancels an in-flight attempt at the deadline. Unlike a retryable failure, this is a policy wall — the operation as a whole has run out of time and the loop stops instead of retrying.
Source
Thrown at python/cocoindex/_internal/deadline.py:188
raise ValueError("retry_transient requires a positive timeout")
if backoff is None:
backoff = exponential_backoff()
scope = _timeout_scope(timeout) if timeout is not None else contextlib.nullcontext()
with scope:
# Exception, not BaseException: doubles as a type-level guard — if
# the except clause below ever widens back to BaseException, this
# assignment becomes a mypy error.
last_error: Exception | None = None
attempt_index = 0
while True:
# Never start an attempt past the deadline. A remaining time of
# exactly zero counts as expired, so a sleep clipped to the
# deadline cannot spin at the boundary.
check_cancellation()
remaining = remaining_seconds()
if remaining is not None and remaining <= 0:
raise DeadlineExceededError("CocoIndex timeout deadline exceeded")
try:
if bound_attempt and remaining is not None:
try:
result = await asyncio.wait_for(fn(), timeout=remaining)
except TimeoutError as timeout_error:
# Translate only a wait_for cancellation at the
# deadline; a TimeoutError raised by fn itself
# before the deadline re-raises as-is.
remaining_now = remaining_seconds()
if remaining_now is not None and remaining_now <= 0:
raise DeadlineExceededError(
"CocoIndex timeout deadline exceeded"
) from timeout_error
raise
else:
result = await fn()
except Exception as error:View on GitHub (pinned to e84aa99b32)
Solutions
- Increase the timeout= budget or raise the enclosing coco.timeout(timedelta(...)) scope to cover the realistic total time including retries.
- Reduce retry pressure: lower max_attempts, increase exponential_backoff initial/max_delay, or narrow retry_on to genuinely transient errors so fatal ones fail fast.
- Make fn() cooperative — await checkpointed calls so the deadline check runs inside attempts, and consider bound_attempt=True to hard-cancel long attempts.
- Catch DeadlineExceededError at the operation boundary and handle it as a timeout (report, reschedule, or propagate), not as a transient failure to retry.
Example fix
// before
with timeout(timedelta(seconds=5)): # too small for N retries
await retry_transient(fn, retry_on=(IOError,), max_attempts=10)
// after
with timeout(timedelta(seconds=60)):
await retry_transient(fn, retry_on=(IOError,), max_attempts=10, bound_attempt=True) Defensive patterns
Strategy: try-catch
Validate before calling
from cocoindex._internal import deadline
remaining = deadline.remaining_seconds()
if remaining is not None and remaining <= 0:
raise RuntimeError("budget already exhausted before starting retries") Type guard
def has_budget(seconds_needed: float) -> bool:
from cocoindex._internal import deadline
r = deadline.remaining_seconds()
return r is None or r > seconds_needed Try / catch
from cocoindex import DeadlineExceededError
try:
result = await retry_transient(fn, retry_on=(IOError,), max_attempts=5, timeout=timeout)
except DeadlineExceededError:
logger.warning("operation exceeded its time budget; giving up")
# treat as timeout: reschedule, report, or propagate — do NOT retry Prevention
- Size timeout= to cover all attempts plus backoff, not just one attempt
- Narrow retry_on so only genuinely transient errors consume budget
- Enable bound_attempt=True for fns that may not yield to the deadline check
- Catch DeadlineExceededError at the operation boundary and treat it as final, not retryable
When it happens
Trigger: The sum of attempt durations plus backoff sleeps exceeds the effective timeout (either the timeout= argument or an ambient coco.timeout() scope); calling retry_transient when an outer deadline is already nearly exhausted; bound_attempt=True with fn() that ignores deadlines and has to be cancelled at the wall.
Common situations: Long-running network/database operations whose transient errors burn the whole budget through repeated retries; nested deadlines where an outer app-level timeout leaves almost nothing for an inner retry loop; slow fn() calls (no awaits that check cancellation) that only get cut off by bound_attempt=True.
Understand the failure class
Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- retry_transient requires a positive timeout
- CocoIndex timeout deadline exceeded
- timeout() requires a datetime.timedelta
- retry_transient requires max_attempts >= 1
- use_mount() requires a ComponentSubpath when the function ha
AI-assisted analysis of cocoindex-io/cocoindex@e84aa99b32 (2026-09-08).
Data as JSON: /api/errors/1c19dd2c489fddb4.
Report an issue: GitHub.