Skip to content

Add-memories timestamps outside years 1 through 9999 in UTC, or with an offset finer than minutes, are refused or shifted by some stores #1795

Description

@edwinyyyu

What happens

Measured on main at ad8ff24, one value at a time through each store's own code, on SQLite and PostgreSQL where a store supports both, with Qdrant 1.17.0 (REST and gRPC) and Milvus 2.6.24 and Milvus Lite. The value is a message's timestamp, which becomes the episode's creation time and its _created_at and _timestamp properties (created_at of an EpisodeEntry).

store 0001-01-01T00:00:00+05:00 or 9999-12-31T23:00:00-05:00 UTC offset with seconds (+05:30:45) UTC offset with a fraction of a second
episode store, SQLite and PostgreSQL refused (OverflowError: date value out of range) stored as its UTC instant stored as its UTC instant
segment store, SQLite and PostgreSQL refused (OverflowError) stored offset cut to whole seconds, instant kept
SQLiteVectorStore, SQLiteVecVectorStore, MilvusVectorStore refused (OverflowError) stored offset cut to whole seconds, instant kept
QdrantVectorStore, REST, gRPC, and local stored offset cut to +05:30 with the same wall clock, so the instant moves by 45 seconds offset dropped with the same wall clock, so the instant moves

Through POST /api/v2/memories with the real stores, on SQLite and on PostgreSQL:

  • timestamp 0001-01-01T00:00:00+05:00: 500, nothing written;
  • timestamp 2026-01-01T12:00:00+05:30:45: 200, stored, so a Qdrant-backed session keeps an instant 45 seconds off.

Why

  • MemoryMessage.timestamp is a plain datetime (packages/common/src/memmachine_common/api/spec.py:466), and its validator takes any offset datetime.fromisoformat reads (:503), seconds and fractions included. EpisodeEntry.created_at is any aware datetime (packages/server/src/memmachine_server/common/episode_store/episode_model.py:35).
  • The episode store, the type-tagged property codec, and the Milvus store convert the value to UTC (packages/server/src/memmachine_server/common/episode_store/episode_sqlalchemy_store.py:220-222, packages/server/src/memmachine_server/common/properties_json.py:54, packages/server/src/memmachine_server/common/vector_store/milvus_vector_store.py:95), which overflows outside years 1 through 9999.
  • The codec keeps the offset in whole seconds (packages/server/src/memmachine_server/common/utils.py:77-80), and the Qdrant store sends the datetime itself (packages/server/src/memmachine_server/common/vector_store/qdrant_vector_store.py:266), whose RFC 3339 form carries the offset in minutes.

Expected

The request refuses such a timestamp with 422 before any store writes, and building an EpisodeEntry with such a created_at raises.

Fix

#1792 types timestamp as PropertyDatetime and checks EpisodeEntry.created_at with the same rule: a UTC offset of whole minutes and a UTC instant in years 1 through 9999.

🤖 Written by Claude Code (Claude Opus 5.5) on behalf of @edwinyyyu.

Activity

  1. added theissue type on Oct 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions