cocoindex-io/cocoindex · error · TypeError
timeout() requires a datetime.timedelta
Error message
timeout() requires a datetime.timedelta
What it means
timeout() applies a cooperative deadline to CocoIndex checkpointed work and validates that the duration is a datetime.timedelta. Passing any other numeric or string duration (int, float seconds, None) raises this TypeError immediately. The library intentionally refuses implicit conversions so callers always express durations explicitly.
Solutions
- Wrap the numeric value: use datetime.timedelta(seconds=30) instead of 30.
- If the value comes from config, parse it into a timedelta at the boundary before entering the timeout scope.
- If you have a non-standard duration object (pandas Timedelta, isodate Duration), convert via timedelta(seconds=obj.total_seconds()).
Example fix
// before
with timeout(30):
...
// after
from datetime import timedelta
with timeout(timedelta(seconds=30)):
... Defensive patterns
Strategy: type-guard
Validate before calling
from datetime import timedelta
def ensure_timedelta(d):
if isinstance(d, (int, float)):
return timedelta(seconds=d)
if not isinstance(d, timedelta):
raise TypeError(f"expected timedelta, got {type(d).__name__}")
return d Type guard
def is_timedelta(v: object) -> bool:
from datetime import timedelta
return isinstance(v, timedelta) Try / catch
try:
with timeout(duration):
...
except TypeError as e:
if 'datetime.timedelta' in str(e):
duration = timedelta(seconds=float(duration))
with timeout(duration): ...
else:
raise Prevention
- Always construct durations with datetime.timedelta, never bare numbers
- Normalize config/env values to timedelta at the parsing boundary
- Add a runtime assertion isinstance(duration, timedelta) in wrapper helpers you write around timeout()
When it happens
Trigger: Calling coco timeout(...) (the deadline context manager in python/cocoindex/_internal/deadline.py:36) with e.g. timeout(30), timeout(0.5), timeout('30s'), or a pandas/numpy Timedelta instead of datetime.timedelta(seconds=30).
Common situations: Developers porting from libraries whose timeout APIs take plain seconds; writing retry helpers that pass through a user-supplied duration without normalizing; config values read as ints from YAML/env being fed straight into the timeout context manager.
Understand the failure class
Background: "invalid duration" / "failed to parse duration": why your timeout, interval, or TTL string is rejected and which formats each library accepts — this error's family across 32 libraries.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- CocoIndex timeout deadline exceeded
- Document key must be a string, got
- Index key must be a (db_key, index_name) tuple, got
- Invalid vector definition
- record_type must be a record type (dataclass, NamedTuple…
AI-assisted analysis of cocoindex-io/cocoindex@e84aa99b32 (2026-09-08).
Data as JSON: /api/errors/867062a327e2d643.
Report an issue: GitHub.
Appendix: source
Thrown at python/cocoindex/_internal/deadline.py:39
_current_deadline: ContextVar[DeadlineContext] = ContextVar(
"coco_deadline", default=core.deadline_none()
)
_logger = logging.getLogger(__name__)
_RetryResultT = TypeVar("_RetryResultT")
# Which failures are safe to retry: an exception-type tuple (isinstance
# semantics, like an `except` clause) or a predicate for classifications
# that inspect status codes or messages.
RetryOn: TypeAlias = tuple[type[Exception], ...] | Callable[[Exception], bool]
@contextlib.contextmanager
def timeout(duration: timedelta) -> Iterator[None]:
"""Apply a cooperative timeout deadline to CocoIndex checkpoints."""
if not isinstance(duration, timedelta):
raise TypeError("timeout() requires a datetime.timedelta")
token = _current_deadline.set(
_current_deadline.get().with_timeout(duration.total_seconds())
)
try:
yield
finally:
_current_deadline.reset(token)
def check_cancellation() -> None:
"""Raise if the current work has been asked to stop.
Deadline expiry is the first cancellation source (raising
``DeadlineExceededError``); future sources (e.g. a batched call whose
callers have all been cancelled) will surface through the same
checkpoint.
"""View on GitHub (pinned to e84aa99b32)