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

  1. Pass `time_at_least=None` (the indexer normally omits it) unless you specifically need drift protection.
  2. Compare clocks before the call: `if time_at_least > record_manager.get_time(): time_at_least = None` or align with `record_manager.get_time()`.
  3. 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).
  4. 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

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


AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14). Data as JSON: /api/errors/39a37c800a2d0bab. Report an issue: GitHub.