[Bug] Passing a negative number for 'n' to 'get_nns_by_item' or 'get_nns_by_vector' causes incorrect results and integer overflow
Author: saitejabandaru-inCreated Jul 20, 2026Updated Jul 20, 2026
When querying an Annoy index using the Python API, if a negative integer (e.g. n = -1) is passed as the n argument to get_nns_by_item or get_nns_by_vector, the function returns completely incorrect results or empty lists [] rather than throwing a Python exception.
Reproduction
from annoy import AnnoyIndex
t = AnnoyIndex(10, 'angular')
for i in range(10):
v = [1 if j == i else 0 for j in range(10)]
t.add_item(i, v)
t.build(10)
# Expected: [0], but gets completely unrelated item or empty list
print(t.get_nns_by_item(0, -1))
print(t.get_nns_by_item(0, -2))Root Cause
In annoymodule.cc, n is parsed as a signed int32_t:
int32_t item, n, search_k=-1, include_distances=0;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii|ii", (char**)kwlist, &item, &n, &search_k, &include_distances))However, in annoylib.h, the corresponding argument is an unsigned size_t n:
void get_nns_by_item(S item, size_t n, int search_k, vector<S>* result, vector<T>* distances) constWhen n = -1 is passed, it is sign-extended to SIZE_MAX (e.g., 18446744073709551615).
This leads to cascading issues in _get_all_nns:
search_kOverflow:search_k = n * _roots.size();overflows. Becausesearch_kisint, it silently wraps around to a negative number.- Unbounded Search Condition:
while (nns.size() < (size_t)search_k && !q.empty())converts the negativesearch_kback toSIZE_MAX, causing the search to attempt exploring the entire tree unbounded. - Garbage Results:
size_t p = n < m ? n : m;evaluates tom(becauseSIZE_MAX < mis false), causing all explored items to be returned. Due to unbounded exploration boundaries, this often yields completely random incorrect items or[].
Suggested Fix
Add a parameter constraint check in annoymodule.cc to ensure n >= 0 before making calls to the C++ core:
if (n < 0) {
PyErr_SetString(PyExc_ValueError, "n must be a non-negative integer");
return NULL;
}Source: spotify/annoy