fix(rag): warn when a duckdb store is empty but files are indexed

A duckdb RAG is two files. The .yaml deliberately carries no vectors, and
open() runs CREATE TABLE IF NOT EXISTS, so a .yaml copied or synced without its
.duckdb sidecar produces a fresh empty store, hydrates to nothing, and answers
every query with nothing while .info rag still lists every indexed file.

Neither existing guard catches it: the anti-wipe check in rebuild_indexes needs
existing > 0, and the mandatory ? on hydration needs a genuine error, while an
absent store is the same Ok(empty) as a RAG with nothing indexed yet.

Warn rather than bail, so a store deleted on purpose still loads and can be
rebuilt.
This commit is contained in:
2026-08-12 11:26:16 -06:00
parent 6f7defe25f
commit 81ed769f8a
+11
View File
@@ -586,6 +586,17 @@ impl Rag {
if data.vectors.is_empty() { if data.vectors.is_empty() {
data.vectors = duck.read_all_vectors()?; data.vectors = duck.read_all_vectors()?;
} }
if data.vectors.is_empty() && !data.files.is_empty() {
println!(
"{} RAG '{name}' lists {} indexed file(s), but its vector store \
'{}' holds no vectors, so every search will return nothing. A \
duckdb RAG is two files: bring the .duckdb sidecar along with \
the .yaml, or re-embed with `.rebuild rag`.",
warning_text("WARNING:"),
data.files.len(),
db_path.display()
);
}
// data.files is always populated for duckdb, so build_bm25() is the only // data.files is always populated for duckdb, so build_bm25() is the only
// path; there is no from-DuckDB fallback. // path; there is no from-DuckDB fallback.
let bm25 = data.build_bm25(); let bm25 = data.build_bm25();