MemPalace/mempalace · error · ValueError
{field_name} must be an ISO date string
Error message
{field_name} must be an ISO date string What it means
ValueError from parse_date_bound (mempalace/date_window.py:49): the value passed for a date filter is not a string at all (None is allowed and means no filter; blank/whitespace strings also mean no filter). The guard exists before any parsing so non-string inputs (ints, datetimes, lists) fail fast with the field's name rather than deep inside fromisoformat.
Source
Thrown at mempalace/date_window.py:49
comparison against drawer ``filed_at`` values, which are stored as naive
local ISO strings (``datetime.now().isoformat()``). Any timezone offset on
the input is dropped so an aware bound never raises a ``TypeError`` against
a naive ``filed_at``. Comparison is therefore wall-clock, which is what the
local-first single-machine model wants; an offset bound is matched on its
wall-clock fields, not its absolute instant, so a bound whose offset differs
from the zone ``filed_at`` was recorded in is matched by clock time.
The accepted grammar is a date, an ISO timestamp (optionally fractional),
and an optional ``Z``/``±HH:MM`` offset; other ISO 8601 forms (basic format,
week dates) are outside the contract and are rejected on the Python 3.9 floor
even where a newer ``fromisoformat`` would accept them.
Blank / whitespace-only means "no filter" (``None``).
Raises ``ValueError`` on an unparseable value so the caller can surface a
clear error, mirroring the wing/room sanitizers.
"""
if value is None:
return None
if not isinstance(value, str):
raise ValueError(f"{field_name} must be an ISO date string")
value = value.strip()
if not value:
return None
# datetime.fromisoformat before Python 3.11 rejects a trailing "Z" (Zulu),
# and appending "+00:00" would break a date-only value on 3.9/3.10
# ("2026-04-01+00:00" is rejected there). Any offset is dropped below for
# wall-clock comparison anyway, so just strip a trailing Z/z; both date and
# date-time Zulu inputs then parse on the 3.9 floor.
iso = value[:-1] if value.endswith(("Z", "z")) else value
try:
parsed = datetime.fromisoformat(iso)
except ValueError as exc:
raise ValueError(
f"{field_name} must be an ISO date string "
f"(e.g. '2026-04-01' or '2026-04-01T09:30:00'), got {value!r}"
) from exc
if parsed.tzinfo is not None:
parsed = parsed.replace(tzinfo=None)View on GitHub (pinned to 06cb6987f0)
Solutions
- Pass ISO 8601 strings: '2026-04-01' or '2026-04-01T09:30:00' (a trailing Z is tolerated).
- Convert datetime objects first: dt.date().isoformat() or dt.isoformat().
- Omit the parameter or pass None/'' when no filter is wanted.
Example fix
# before results = search(since=start_dt) # datetime object # after results = search(since=start_dt.date().isoformat())
Defensive patterns
Strategy: type-guard
Validate before calling
def as_iso_or_none(value):
if value is None or (isinstance(value, str) and not value.strip()):
return None
if not isinstance(value, str):
raise TypeError("date filter must be an ISO string")
return value Type guard
from datetime import date, datetime
def is_iso_date_str(value: object) -> bool:
if not isinstance(value, str) or not value.strip():
return False
try:
datetime.fromisoformat(value.rstrip("Zz"))
return True
except ValueError:
return False Try / catch
try:
since_dt, before_dt = parse_window(since, before)
except ValueError as exc:
raise UserInputError(str(exc)) from exc # surface to the caller; no retry Prevention
- Coerce datetimes/dates to .isoformat() at the API boundary.
- Validate MCP tool inputs (numbers vs strings) before calling search APIs.
- Pass None or '' to express 'no filter' rather than 0 or empty objects.
When it happens
Trigger: Passing since=20260401 (int), before=datetime.now(), or a date object instead of an ISO string to search/list APIs that accept date windows; MCP tool callers sending a JSON number instead of a string; programmatic callers reusing datetime objects from other APIs.
Common situations: MCP/JSON tool boundaries where types loosen (number-vs-string); refactoring call sites from datetimes to strings incompletely; Python callers assuming the API accepts datetime like other libraries do.
Related errors
- since ({since!r}) must be earlier than before ({before!r})
- {field_name} must be an ISO date string (e.g. '2026-04-01' o
- {type(self).name} does not advertise supports_namespace_isol
- operator {key!r} not supported by chroma backend
- ChromaBackend has been closed
AI-assisted analysis of MemPalace/mempalace@06cb6987f0 (2026-08-15).
Data as JSON: /api/errors/34ff17069b5347e8.
Report an issue: GitHub.