From 9eeee6178cd6aaa7655914bd784bb853e60a1c70 Mon Sep 17 00:00:00 2001 From: Soby Chacko Date: Thu, 15 May 2025 19:37:52 -0400 Subject: [PATCH] GH-3181: fix: Validate index name exists in CassandraVectorStore Fixes: #3181 https://github.com/spring-projects/spring-ai/issues/3181 When using CassandraVectorStore with an invalid index name and initializeSchema=false, the application would throw a generic NoSuchElementException from Optional.get() with message "No value present" when trying to access the index metadata. Changes: - Added explicit validation of index existence in checkSchemaValid() method - Improved error handling in getIndexSimilarity() method to provide a clear error message when an index doesn't exist - Added integration test to verify proper error handling with invalid index names Signed-off-by: Soby Chacko --- .../cassandra/CassandraVectorStore.java | 19 ++++++++++---- .../cassandra/CassandraVectorStoreIT.java | 25 +++++++++++++++++++ 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/vector-stores/spring-ai-cassandra-store/src/main/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStore.java b/vector-stores/spring-ai-cassandra-store/src/main/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStore.java index f6d8ad475..46bb76d03 100644 --- a/vector-stores/spring-ai-cassandra-store/src/main/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStore.java +++ b/vector-stores/spring-ai-cassandra-store/src/main/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStore.java @@ -43,6 +43,7 @@ import com.datastax.oss.driver.api.core.cql.Row; import com.datastax.oss.driver.api.core.cql.SimpleStatement; import com.datastax.oss.driver.api.core.data.CqlVector; import com.datastax.oss.driver.api.core.metadata.schema.ColumnMetadata; +import com.datastax.oss.driver.api.core.metadata.schema.IndexMetadata; import com.datastax.oss.driver.api.core.metadata.schema.TableMetadata; import com.datastax.oss.driver.api.core.type.DataType; import com.datastax.oss.driver.api.core.type.DataTypes; @@ -397,11 +398,16 @@ public class CassandraVectorStore extends AbstractObservationVectorStore impleme private Similarity getIndexSimilarity(TableMetadata metadata) { - return Similarity.valueOf(metadata.getIndex(this.schema.index()) - .get() - .getOptions() - .getOrDefault("similarity_function", "COSINE") - .toUpperCase()); + Optional indexMetadata = metadata.getIndex(this.schema.index()); + + if (indexMetadata.isEmpty()) { + throw new IllegalStateException( + String.format("Index %s does not exist in table %s", this.schema.index(), this.schema.table)); + } + + return Similarity + .valueOf(indexMetadata.get().getOptions().getOrDefault("similarity_function", "COSINE").toUpperCase()); + } private PreparedStatement prepareDeleteStatement() { @@ -554,6 +560,9 @@ public class CassandraVectorStore extends AbstractObservationVectorStore impleme .getTable(this.schema.table) .get(); + Preconditions.checkState(tableMetadata.getIndex(this.schema.index()).isPresent(), "index %s does not exist", + this.schema.index()); + Preconditions.checkState(tableMetadata.getColumn(this.schema.content).isPresent(), "column %s does not exist", this.schema.content); diff --git a/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStoreIT.java b/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStoreIT.java index 26327e81d..a5993b9c2 100644 --- a/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStoreIT.java +++ b/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStoreIT.java @@ -522,6 +522,31 @@ class CassandraVectorStoreIT extends BaseVectorStoreTests { }); } + @Test + void throwsExceptionOnInvalidIndexNameWithSchemaValidation() { + this.contextRunner.run(context -> { + // Create valid schema first, then close + try (CassandraVectorStore validStore = createTestStore(context, new SchemaColumn("meta1", DataTypes.TEXT), + new SchemaColumn("meta2", DataTypes.TEXT))) { + // Nothing to do here. This should not fail as the Schema now exists + } + + // Now try with invalid index name but don't reinitialize schema + CassandraVectorStore.Builder invalidBuilder = storeBuilder(context.getBean(CqlSession.class), + context.getBean(EmbeddingModel.class)) + .addMetadataColumns(new SchemaColumn("meta1", DataTypes.TEXT), + new SchemaColumn("meta2", DataTypes.TEXT)) + .indexName("non_existent_index_name") + .initializeSchema(false); + + IllegalStateException exception = Assertions.assertThrows(IllegalStateException.class, + invalidBuilder::build); + + assertThat(exception.getMessage()).contains("non_existent_index_name"); + assertThat(exception.getMessage()).contains("does not exist"); + }); + } + @SpringBootConfiguration @EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class }) public static class TestApplication {