headroomlabs-ai/headroom · error · ValueError
metadata ({len(metadata)}) must match memory_ids ({len(memor
Error message
metadata ({len(metadata)}) must match memory_ids ({len(memory_ids)}) length What it means
Second invariant check in FTS5TextIndex.index_batch: when an optional metadata list is supplied, it must have exactly one dict per memory_id (same length), so each indexed row gets its metadata in the single transaction. Raised immediately after the ids/texts length check passes.
Source
Thrown at headroom/memory/adapters/fts5.py:167
metadata: list[dict] | None = None,
) -> None:
"""Index multiple memories in a single transaction.
Args:
memory_ids: List of unique identifiers.
texts: List of text contents to index.
metadata: Optional list of metadata dicts (one per memory).
Raises:
ValueError: If memory_ids and texts have different lengths.
"""
if len(memory_ids) != len(texts):
raise ValueError(
f"memory_ids ({len(memory_ids)}) and texts ({len(texts)}) must have same length"
)
if metadata is not None and len(metadata) != len(memory_ids):
raise ValueError(
f"metadata ({len(metadata)}) must match memory_ids ({len(memory_ids)}) length"
)
metadata = metadata or [{} for _ in memory_ids]
with self._get_conn() as conn:
# Delete existing entries
conn.executemany(
"DELETE FROM memory_fts WHERE memory_id = ?",
[(mid,) for mid in memory_ids],
)
# Prepare batch data
batch_data = []
for memory_id, text, meta in zip(memory_ids, texts, metadata):
user_id = meta.get("user_id", "")
session_id = meta.get("session_id", "")
category = "" # Deprecated - kept for backwards compatibilityView on GitHub (pinned to 322425c43b)
Solutions
- Compare the counts in the message; regenerate metadata with a list comprehension over memory_ids so lengths lock together.
- If metadata is unknown for some rows, pad with empty dicts: metadata=[m.get(mid, {}) for mid in memory_ids].
- Omit the metadata argument entirely when you don't have per-id data — it's optional.
- Add a unit assertion on all three lengths at your batch producer.
Example fix
# before
index.index_batch(ids, texts, metadata=uniq_metadata) # 10 ids, 7 metadata -> ValueError
# after
meta_by_id = dict(zip(ids, uniq_metadata_list))
index.index_batch(ids, texts, metadata=[meta_by_id.get(mid, {}) for mid in ids]) Defensive patterns
Strategy: validation
Validate before calling
ids = [m.id for m in memories]
texts = [m.text for m in memories]
meta = [m.metadata or {} for m in memories] # derived from the SAME iterable
assert len(ids) == len(texts) == len(meta) Try / catch
try:
index.index_batch(ids, texts, metadata=meta)
except ValueError as e:
if "must match memory_ids" in str(e):
meta = [meta_by_id.get(mid, {}) for mid in ids] # rebuild aligned
index.index_batch(ids, texts, metadata=meta)
else:
raise Prevention
- Derive all parallel lists from one source iterable of records.
- Default missing metadata to {} per id rather than dropping entries.
- Skip the metadata argument when data is incomplete instead of passing a short list.
When it happens
Trigger: Calling index_batch(ids, texts, metadata=...) where metadata was built per-text, per-chunk, per-unique-record, or filtered independently — any producer whose count diverges from len(memory_ids).
Common situations: Deduplicating metadata but not ids; metadata computed only for successful lookups (missing key skipped silently); chunked texts with metadata per original doc; reusing a cached metadata list after the id list changed.
Related errors
- memory_ids ({len(memory_ids)}) and texts ({len(texts)}) must
- bedrock_eventstream_parse_failed
- max_size must be at least 1, got {max_size}
- save_path must be provided when auto_save is True
- Memory {old_memory_id} not found
AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15).
Data as JSON: /api/errors/a578fd287aa94e83.
Report an issue: GitHub.