mirror of
https://github.com/cocoindex-io/cocoindex-code.git
synced 2026-09-14 16:39:38 +08:00
9fd2e7470a
Issue #270 reported `ccc search --path` crashing with `TypeError: unsupported operand type(s) for *: 'NoneType' and 'NoneType'`. The crash could not be reproduced, and the reported root cause does not hold: `vec_distance_L2` never returns NULL, it raises (verified against sqlite-vec 0.1.6-0.1.9, SQLite 3.46/3.53, multi-chunk tables and re-index churn). What the report did expose is that the failure was undiagnosable. Two gaps, both fixed here: - The daemon's search handler discarded the traceback (`ErrorResponse(message=str(e))`), so the reporter saw only the client's re-raise frames. It now sends `traceback.format_exc()` and logs the exception; `_dispatch` does the same. On the client, the `raise RuntimeError(f"Daemon error: ...")` pattern was duplicated at five sites and only `doctor()` appended `resp.traceback` -- the search path, which the reporter came through, dropped it. Consolidated into one `_daemon_error()` helper used by all five. - `_knn_query` now rejects rows with a NULL distance, raising a specific error naming the query shape and offending file instead of dying in `_l2_to_score`. `distance` is a hidden vec0 column that sqlite-vec populates only under the KNN query plan and returns NULL for on a full scan, so a NULL means the plan we asked for is not the plan we got. The guard lives in `_knn_query` rather than the caller because the multi-language merge path sorts on `r[5]` in `heapq.nsmallest`, where a NULL would fail on `None < float` before any caller-side check ran. `_full_scan_query` needs no guard: it computes `vec_distance_L2(...)` itself, which works under any plan and raises rather than returning NULL on bad input. The new tests build a real in-memory vec0 table with the indexer's exact DDL (no embedding model, ~0.2s) and cover both that `--path` filtering yields usable distances and that the bare-`distance`-under-full-scan shape is the one that does not. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>