spring-projects/spring-ai · error · RuntimeException
Similarity threshold filtering requires all vectors to be…
Error message
Similarity threshold filtering requires all vectors to be normalized, see the forcedNormalization parameter for this Vector store. Also only COSINE and DOT distance types are supported.
What it means
OracleVectorStore.doSimilaritySearch throws this RuntimeException when a similarity threshold is used but the store cannot guarantee meaningful threshold math: either forcedNormalization was not enabled or the configured distance type is not COSINE or DOT. Threshold filtering requires normalized vectors so distance can be derived from similarity.
Solutions
- Set forcedNormalization(true) in the OracleVectorStore builder and re-ingest vectors so they are normalized.
- Switch the distance type to COSINE or DOT via OracleVectorStoreDistanceType.
- Set the search threshold to 0 if you cannot normalize vectors, and filter results in application code instead.
- Verify existing rows are normalized (L2 norm = 1) before enabling threshold filtering.
Example fix
// before
OracleVectorStore.builder(jdbcTemplate, embeddingModel)
.distanceType(OracleVectorStoreDistanceType.EUCLIDEAN)
.build();
request.withSimilarityThreshold(0.7); // throws
// after
OracleVectorStore.builder(jdbcTemplate, embeddingModel)
.forcedNormalization(true)
.distanceType(OracleVectorStoreDistanceType.COSINE)
.build(); Defensive patterns
Strategy: validation
Validate before calling
boolean thresholdUsable = store.isForcedNormalization()
&& (store.getDistanceType() == OracleVectorStoreDistanceType.COSINE
|| store.getDistanceType() == OracleVectorStoreDistanceType.DOT);
if (!thresholdUsable) request = request.withSimilarityThreshold(0); Try / catch
try {
vectorStore.similaritySearch(request.withSimilarityThreshold(0.75));
} catch (RuntimeException e) {
if (e.getMessage().contains("Similarity threshold filtering requires")) {
results = vectorStore.similaritySearch(request.withSimilarityThreshold(0)); // post-filter in app
}
} Prevention
- Enable forcedNormalization(true) in the builder when using thresholds
- Use COSINE or DOT distance types whenever thresholds matter
- Re-ingest after changing normalization settings so old vectors match
- Verify stored vectors have L2 norm 1 before threshold filtering
When it happens
Trigger: Calling similaritySearch(SearchRequest) with a similarityThreshold > 0 on an OracleVectorStore built without forcedNormalization=true, or with OracleVectorStoreDistanceType.EUCLIDEAN / other non-COSINE/DOT distance.
Common situations: Default builder config (no forcedNormalization) combined with a nonzero threshold; switching distance type to EUCLIDEAN for legacy data while keeping threshold logic; documents ingested without L2 normalization.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- Failed to delete documents by filter
- Bad Request
- Cannot compare values of incompatible types
- Cannot compare values of incompatible types
- Cannot compare values of types
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/9645e3095bffcc87.
Report an issue: GitHub.
Appendix: source
Thrown at vector-stores/spring-ai-oracle-store/src/main/java/org/springframework/ai/vectorstore/oracle/OracleVectorStore.java:418
select id, content, metadata, embedding, %sVECTOR_DISTANCE(embedding, ?, %s)%s as distance
from %s
%sorder by distance
fetch EXACT first %d rows only""",
this.distanceType == OracleVectorStore.OracleVectorStoreDistanceType.DOT ? "(1+" : "",
this.distanceType.name(),
this.distanceType == OracleVectorStore.OracleVectorStoreDistanceType.DOT ? ")/2" : "",
this.tableName, jsonPathFilter, request.getTopK());
if (logger.isDebugEnabled()) {
logger.debug("SQL query: " + sql);
}
return this.jdbcTemplate.query(sql, new DocumentRowMapper(), embeddingVector);
}
else {
if (!this.forcedNormalization || (this.distanceType != OracleVectorStoreDistanceType.COSINE
&& this.distanceType != OracleVectorStore.OracleVectorStoreDistanceType.DOT)) {
throw new RuntimeException(
"Similarity threshold filtering requires all vectors to be normalized, see the forcedNormalization parameter for this Vector store. Also only COSINE and DOT distance types are supported.");
}
final double distance = this.distanceType == OracleVectorStore.OracleVectorStoreDistanceType.DOT
? (1d - request.getSimilarityThreshold()) * 2d - 1d : 1d - request.getSimilarityThreshold();
if (StringUtils.hasText(nativeFilterExpression)) {
jsonPathFilter = " and " + nativeFilterExpression;
}
final String sql = this.distanceType == OracleVectorStore.OracleVectorStoreDistanceType.DOT
? (this.searchAccuracy == DEFAULT_SEARCH_ACCURACY
? String.format(
"""
select id, content, metadata, embedding, (1+VECTOR_DISTANCE(embedding, ?, DOT))/2 as distance
from %s
where VECTOR_DISTANCE(embedding, ?, DOT) <= ?%s
order by distanceView on GitHub (pinned to 98a7beda4f)