alibaba/nacos · critical · NacosException
AI resource {channel} recall exceeded configured candidate l
Error message
AI resource {channel} recall exceeded configured candidate limit {limit} What it means
A SERVER_ERROR (HTTP 500) from ensureWithinRecallLimit: a search recall channel (vector or keyword) returned more hits than the configured candidate ceiling. The service deliberately requests limit+1 from the repository so that exceeding the limit is detectable; breaching it means the storage/vector index did not honor the LIMIT clause. The ceiling defaults to 10000 and is tunable via nacos.ai.resource.search.max-recall-candidates.
Source
Thrown at ai/src/main/java/com/alibaba/nacos/ai/service/search/AiResourceSearchService.java:344
maxCandidates + 1));
ensureWithinRecallLimit(vectorHits, maxCandidates, "vector");
for (AiResourceSearchHit hit : vectorHits) {
recordMaxScore(scores, hit);
}
}
List<AiResourceSearchHit> keywordHits = repository.searchChunks(query.getNamespaceId(),
query.getText(), query.getResourceTypes(), maxCandidates + 1);
ensureWithinRecallLimit(keywordHits, maxCandidates, "keyword");
for (AiResourceSearchHit hit : keywordHits) {
recordMaxScore(scores, hit);
}
return scores;
}
private void ensureWithinRecallLimit(List<AiResourceSearchHit> hits, int limit, String channel)
throws NacosException {
if (hits != null && hits.size() > limit) {
throw new NacosException(NacosException.SERVER_ERROR,
"AI resource " + channel + " recall exceeded configured candidate limit "
+ limit);
}
}
private List<AiResourceSearchDocument> findDocumentsByIds(Collection<Long> documentIds) {
if (documentIds == null || documentIds.isEmpty()) {
return Collections.emptyList();
}
List<Long> ids = new ArrayList<>(documentIds);
List<AiResourceSearchDocument> result = new ArrayList<>();
for (int offset = 0; offset < ids.size(); offset += DOCUMENT_LOOKUP_BATCH_SIZE) {
int toIndex = Math.min(offset + DOCUMENT_LOOKUP_BATCH_SIZE, ids.size());
result.addAll(repository.findEntriesByIds(ids.subList(offset, toIndex)));
}
return result;
}
View on GitHub (pinned to 9b989acdf1)
Solutions
- Check the configured value of nacos.ai.resource.search.max-recall-candidates and raise it if it was set too low.
- Inspect the active AiResourceSearchRepository / AiResourceVectorIndex implementation for the configured storage dialect and confirm it applies LIMIT correctly.
- If the value is sane and recall still exceeds it, treat it as a defect in the storage/vector plugin and file a bug.
- As a stopgap, narrow the query (resourceTypes filter) to reduce recall volume.
Defensive patterns
Strategy: try-catch
Try / catch
try {
Page result = searchService.search(query);
} catch (NacosException e) {
if (e.getErrCode() == NacosException.SERVER_ERROR
&& e.getErrMsg().contains("recall exceeded configured candidate limit")) {
// degrade: narrow resourceTypes filter or fall back to keyword-only/empty result
return degradedSearch(query);
} else {
throw e;
}
} Prevention
- Keep nacos.ai.resource.search.max-recall-candidates at or above expected recall volume.
- Verify any new storage-dialect/vector-index plugin honors LIMIT before enabling.
- Re-test search after dialect or vector-index upgrades.
- Do not set max-recall-candidates to an artificially tiny value.
When it happens
Trigger: Any search query while the active AiResourceSearchRepository or AiResourceVectorIndex returns an unbounded/larger-than-requested result set, or while max-recall-candidates is set below the real recall volume. Raised for the 'vector' channel when the vector index over-returns and for 'keyword' when the chunk repository over-returns.
Common situations: A new or updated storage-dialect plugin whose LIMIT handling is broken; a vector index implementation changed to return the full top-k set; someone set max-recall-candidates to an absurdly small number; very large corpus plus a broken SQL LIMIT for the dialect.
Related errors
AI-assisted analysis of alibaba/nacos@9b989acdf1 (2026-08-14).
Data as JSON: /api/errors/74e426408861bb54.
Report an issue: GitHub.