langchain-ai/langchain · error · ValueError
time_at_least must be in the past
Error message
time_at_least must be in the past
What it means
`ValueError` from `RecordManager.update`/`aupdate`: the `time_at_least` argument is a timestamp greater than the record manager's current clock (`get_time()`). The indexer uses this to guard against time-drift — if the caller believes more time has passed than the store's clock shows, updates could be ordered incorrectly, so the write is rejected.
Source
Thrown at libs/core/langchain_core/indexing/base.py:303
E.g., use to validate that the time in the postgres database
is equal to or larger than the given timestamp, if not
raise an error.
This is meant to help prevent time-drift issues since
time may not be monotonically increasing!
Raises:
ValueError: If the length of keys doesn't match the length of group
ids.
ValueError: If time_at_least is in the future.
"""
if group_ids and len(keys) != len(group_ids):
msg = "Length of keys must match length of group_ids"
raise ValueError(msg)
for index, key in enumerate(keys):
group_id = group_ids[index] if group_ids else None
if time_at_least and time_at_least > self.get_time():
msg = "time_at_least must be in the past"
raise ValueError(msg)
self.records[key] = {"group_id": group_id, "updated_at": self.get_time()}
async def aupdate(
self,
keys: Sequence[str],
*,
group_ids: Sequence[str | None] | None = None,
time_at_least: float | None = None,
) -> None:
"""Async upsert records into the database.
Args:
keys: A list of record keys to upsert.
group_ids: A list of group IDs corresponding to the keys.
time_at_least: Optional timestamp. Implementation can use this
to optionally verify that the timestamp IS at least this time
in the system that stores.View on GitHub (pinned to e32fa9a52e)
Solutions
- Pass `time_at_least=None` (the indexer normally omits it) unless you specifically need drift protection.
- Compare clocks before the call: `if time_at_least > record_manager.get_time(): time_at_least = None` or align with `record_manager.get_time()`.
- Fix the clock skew: sync NTP on app hosts and the DB server, or verify you are using the same time unit (seconds vs ms).
- If you control the manager, make `get_time()` and `time_at_least` use one source of truth (e.g. both DB time or both app time).
Example fix
# before record_manager.update(keys, time_at_least=time.time() * 1000) # ms vs s drift # after record_manager.update(keys, time_at_least=None) # or record_manager.update(keys, time_at_least=record_manager.get_time())
Defensive patterns
Strategy: validation
Validate before calling
if time_at_least is not None and time_at_least > record_manager.get_time():
logger.warning("time_at_least ahead of record manager clock; omitting it")
time_at_least = None
record_manager.update(keys, time_at_least=time_at_least) Type guard
null
Try / catch
try:
record_manager.update(keys, time_at_least=ts)
except ValueError as e:
if "time_at_least must be in the past" in str(e):
record_manager.update(keys) # retry without the drift guard
else:
raise Prevention
- Prefer time_at_least=None unless you specifically need drift protection
- Sync clocks (NTP/chrony) on app hosts and the record manager database
- Use record_manager.get_time() as your timestamp source instead of time.time()
When it happens
Trigger: Calling `record_manager.update(keys, time_at_least=ts)` with `ts > record_manager.get_time()`. In practice this fires when the client machine's clock is ahead of the record manager's database clock (e.g. SQL-backed managers using the DB clock), or a caller passes milliseconds against a seconds-based clock.
Common situations: Clock skew between app servers and the database hosting the record manager; passing a Unix timestamp in milliseconds (`time.time()*1000`) to a seconds-based manager; timezone/DST arithmetic bugs producing future timestamps; NTP not synced in containers.
Related errors
- Length of keys must match length of group_ids
- invalid IP address
- Failed to resolve hostname '{hostname}': {e}
- Network error while validating URL: {e}
- maxsize must be greater than 0
AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14).
Data as JSON: /api/errors/39a37c800a2d0bab.
Report an issue: GitHub.