headroomlabs-ai/headroom · error · ValueError
memory_ids ({len(memory_ids)}) and texts ({len(texts)}) must
Error message
memory_ids ({len(memory_ids)}) and texts ({len(texts)}) must have same length What it means
FTS5TextIndex.index_batch validates that its parallel list arguments have identical lengths before touching SQLite; memory_ids and texts must pair one-to-one. This ValueError fails fast so the executemany DELETE/INSERT inside a single transaction never processes misaligned rows.
Source
Thrown at headroom/memory/adapters/fts5.py:162
def index_batch(
self,
memory_ids: list[str],
texts: list[str],
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 dataView on GitHub (pinned to 322425c43b)
Solutions
- Inspect the two counts in the message to find where the divergence starts.
- Build pairs and derive both lists from one structure: [(mid, text), ...] so they cannot drift.
- If chunking, repeat the memory_id per chunk instead of producing separate-length lists.
- Add an assert len(ids) == len(texts) in your producer code near the source of the mismatch.
Example fix
# before index.index_batch(ids, chunked_texts) # 10 ids, 23 chunks -> ValueError # after pairs = [(mid, chunk) for mid, chunks in zip(ids, chunked) for chunk in chunks] index.index_batch([p[0] for p in pairs], [p[1] for p in pairs])
Defensive patterns
Strategy: validation
Validate before calling
def valid_batch(ids: list[str], texts: list[str], metadata: list | None) -> bool:
"""True when index_batch's parallel-array invariants hold."""
if len(ids) != len(texts):
return False
return metadata is None or len(metadata) == len(ids) Try / catch
try:
index.index_batch(ids, texts)
except ValueError as e:
if "must have same length" in str(e):
raise SystemExit(f"producer bug: ragged batch ({e}); fix upstream list construction") from e
raise Prevention
- Build (id, text) pairs first and unzip, so the lists cannot diverge.
- Add len() assertions in the batch producer right where filtering happens.
- Cover the batch producer with a unit test asserting equal lengths.
When it happens
Trigger: Calling index_batch(memory_ids, texts) where the lists differ in length — e.g. ids generated per unique memory but texts per chunk, zipping that dropped elements, or a filtered list applied to only one of the two arguments.
Common situations: Chunking/dedup pipelines that shrink one list and not the other; batch code that appends ids for successful extractions but texts for all inputs; upstream scanner returning ragged batches; off-by-one slicing.
Related errors
- metadata ({len(metadata)}) must match memory_ids ({len(memor
- 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/79116f595a16e210.
Report an issue: GitHub.