Skip to content

Commit a14f79a

Browse files
committed
fix(vector-io): handle missing document_id in insert_chunks
Fixed KeyError when chunks don't have document_id in metadata or chunk_metadata. Updated logging to safely extract document_id using getattr and RAG memory to handle different document_id locations. Added test for missing document_id scenarios. Fixes issue #3494 where /v1/vector-io/insert would crash with KeyError.
1 parent a50b639 commit a14f79a

File tree

3 files changed

+29
-3
lines changed

3 files changed

+29
-3
lines changed

llama_stack/core/routers/vector_io.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,11 +101,15 @@ async def insert_chunks(
101101
chunks: list[Chunk],
102102
ttl_seconds: int | None = None,
103103
) -> None:
104+
doc_ids = [
105+
getattr(chunk.chunk_metadata, "document_id", None) if chunk.chunk_metadata else None for chunk in chunks[:3]
106+
]
104107
logger.debug(
105-
f"VectorIORouter.insert_chunks: {vector_db_id}, {len(chunks)} chunks, ttl_seconds={ttl_seconds}, chunk_ids={[chunk.metadata['document_id'] for chunk in chunks[:3]]}{' and more...' if len(chunks) > 3 else ''}",
108+
f"VectorIORouter.insert_chunks: {vector_db_id}, {len(chunks)} chunks, "
109+
f"ttl_seconds={ttl_seconds}, chunk_ids={doc_ids}{' and more...' if len(chunks) > 3 else ''}"
106110
)
107111
provider = await self.routing_table.get_provider_impl(vector_db_id)
108-
return await provider.insert_chunks(vector_db_id, chunks, ttl_seconds)
112+
await provider.insert_chunks(vector_db_id, chunks, ttl_seconds)
109113

110114
async def query_chunks(
111115
self,

llama_stack/providers/inline/tool_runtime/rag/memory.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,10 @@ async def query(
279279
return RAGQueryResult(
280280
content=picked,
281281
metadata={
282-
"document_ids": [c.metadata["document_id"] for c in chunks[: len(picked)]],
282+
"document_ids": [
283+
c.metadata.get("document_id") or (c.chunk_metadata.document_id if c.chunk_metadata else None)
284+
for c in chunks[: len(picked)]
285+
],
283286
"chunks": [c.content for c in chunks[: len(picked)]],
284287
"scores": scores[: len(picked)],
285288
"vector_db_ids": [c.metadata["vector_db_id"] for c in chunks[: len(picked)]],

tests/unit/providers/vector_io/test_vector_io_openai_vector_stores.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,25 @@ async def test_insert_chunks_missing_db_raises(vector_io_adapter):
113113
await vector_io_adapter.insert_chunks("db_not_exist", [])
114114

115115

116+
async def test_insert_chunks_with_missing_document_id(vector_io_adapter):
117+
"""Ensure no KeyError when document_id is missing or in different places."""
118+
from llama_stack.apis.vector_io import Chunk, ChunkMetadata
119+
120+
fake_index = AsyncMock()
121+
vector_io_adapter.cache["db1"] = fake_index
122+
123+
# Various document_id scenarios that shouldn't crash
124+
chunks = [
125+
Chunk(content="has doc_id in metadata", metadata={"document_id": "doc-1"}),
126+
Chunk(content="no doc_id anywhere", metadata={"source": "test"}),
127+
Chunk(content="doc_id in chunk_metadata", chunk_metadata=ChunkMetadata(document_id="doc-3")),
128+
]
129+
130+
# Should work without KeyError
131+
await vector_io_adapter.insert_chunks("db1", chunks)
132+
fake_index.insert_chunks.assert_awaited_once()
133+
134+
116135
async def test_query_chunks_calls_underlying_index_and_returns(vector_io_adapter):
117136
expected = QueryChunksResponse(chunks=[Chunk(content="c1")], scores=[0.1])
118137
fake_index = AsyncMock(query_chunks=AsyncMock(return_value=expected))

0 commit comments

Comments
 (0)