Skip to content

Commit def222f

Browse files
authored
Enhance error handling for collection checks on initialize (#3937)
1 parent b396224 commit def222f

File tree

2 files changed

+67
-60
lines changed

2 files changed

+67
-60
lines changed

src/services/code-index/vector-store/__tests__/qdrant-client.test.ts

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -201,19 +201,23 @@ describe("QdrantVectorStore", () => {
201201
expect(mockQdrantClientInstance.createPayloadIndex).toHaveBeenCalledTimes(5)
202202
;(console.warn as jest.Mock).mockRestore() // Restore console.warn
203203
})
204-
it("should re-throw error from getCollection if it is not a 404 error", async () => {
204+
it("should log warning for non-404 errors but still create collection", async () => {
205205
const genericError = new Error("Generic Qdrant Error")
206206
mockQdrantClientInstance.getCollection.mockRejectedValue(genericError)
207-
jest.spyOn(console, "error").mockImplementation(() => {}) // Suppress console.error
207+
jest.spyOn(console, "warn").mockImplementation(() => {}) // Suppress console.warn
208208

209-
await expect(vectorStore.initialize()).rejects.toThrow(genericError)
209+
const result = await vectorStore.initialize()
210210

211+
expect(result).toBe(true) // Collection was created
211212
expect(mockQdrantClientInstance.getCollection).toHaveBeenCalledTimes(1)
212-
expect(mockQdrantClientInstance.createCollection).not.toHaveBeenCalled()
213+
expect(mockQdrantClientInstance.createCollection).toHaveBeenCalledTimes(1)
213214
expect(mockQdrantClientInstance.deleteCollection).not.toHaveBeenCalled()
214-
expect(mockQdrantClientInstance.createPayloadIndex).not.toHaveBeenCalled()
215-
expect(console.error).toHaveBeenCalledTimes(2) // Once in the try/catch for getCollection, once in the outer try/catch
216-
;(console.error as jest.Mock).mockRestore()
215+
expect(mockQdrantClientInstance.createPayloadIndex).toHaveBeenCalledTimes(5)
216+
expect(console.warn).toHaveBeenCalledWith(
217+
expect.stringContaining(`Warning during getCollectionInfo for "${expectedCollectionName}"`),
218+
genericError.message,
219+
)
220+
;(console.warn as jest.Mock).mockRestore()
217221
})
218222
it("should re-throw error from createCollection when no collection initially exists", async () => {
219223
mockQdrantClientInstance.getCollection.mockRejectedValue({
@@ -260,7 +264,7 @@ describe("QdrantVectorStore", () => {
260264
for (let i = 0; i <= 4; i++) {
261265
expect(console.warn).toHaveBeenCalledWith(
262266
expect.stringContaining(`Could not create payload index for pathSegments.${i}`),
263-
indexError,
267+
indexError.message,
264268
)
265269
}
266270

@@ -322,17 +326,20 @@ describe("QdrantVectorStore", () => {
322326
expect(mockQdrantClientInstance.getCollection).toHaveBeenCalledWith(expectedCollectionName)
323327
})
324328

325-
it("should return false and log error for non-404 errors", async () => {
329+
it("should return false and log warning for non-404 errors", async () => {
326330
const genericError = new Error("Network error")
327331
mockQdrantClientInstance.getCollection.mockRejectedValue(genericError)
328-
jest.spyOn(console, "error").mockImplementation(() => {})
332+
jest.spyOn(console, "warn").mockImplementation(() => {})
329333

330334
const result = await vectorStore.collectionExists()
331335

332336
expect(result).toBe(false)
333337
expect(mockQdrantClientInstance.getCollection).toHaveBeenCalledTimes(1)
334-
expect(console.error).toHaveBeenCalledWith("Error checking collection existence:", genericError)
335-
;(console.error as jest.Mock).mockRestore()
338+
expect(console.warn).toHaveBeenCalledWith(
339+
expect.stringContaining(`Warning during getCollectionInfo for "${expectedCollectionName}"`),
340+
genericError.message,
341+
)
342+
;(console.warn as jest.Mock).mockRestore()
336343
})
337344
describe("collectionExists", () => {
338345
// Test scenarios for collectionExists will go here

src/services/code-index/vector-store/qdrant-client.ts

Lines changed: 48 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { QdrantClient } from "@qdrant/js-client-rest"
1+
import { QdrantClient, Schemas } from "@qdrant/js-client-rest"
22
import { createHash } from "crypto"
33
import * as path from "path"
44
import { getWorkspacePath } from "../../../utils/path"
@@ -37,74 +37,83 @@ export class QdrantVectorStore implements IVectorStore {
3737
this.collectionName = `ws-${hash.substring(0, 16)}`
3838
}
3939

40+
private async getCollectionInfo(): Promise<Schemas["CollectionInfo"] | null> {
41+
try {
42+
const collectionInfo = await this.client.getCollection(this.collectionName)
43+
return collectionInfo
44+
} catch (error: unknown) {
45+
if (error instanceof Error) {
46+
console.warn(
47+
`[QdrantVectorStore] Warning during getCollectionInfo for "${this.collectionName}". Collection may not exist or another error occurred:`,
48+
error.message,
49+
)
50+
}
51+
return null
52+
}
53+
}
54+
4055
/**
4156
* Initializes the vector store
4257
* @returns Promise resolving to boolean indicating if a new collection was created
4358
*/
4459
async initialize(): Promise<boolean> {
60+
let created = false
4561
try {
46-
let created = false
47-
48-
try {
49-
// Directly attempt to fetch the specific collection
50-
const collectionInfo = await this.client.getCollection(this.collectionName)
62+
const collectionInfo = await this.getCollectionInfo()
5163

52-
// Collection exists - check if vector size matches
64+
if (collectionInfo === null) {
65+
// Collection info not retrieved (assume not found or inaccessible), create it
66+
await this.client.createCollection(this.collectionName, {
67+
vectors: {
68+
size: this.vectorSize,
69+
distance: this.DISTANCE_METRIC,
70+
},
71+
})
72+
created = true
73+
} else {
74+
// Collection exists, check vector size
5375
const existingVectorSize = collectionInfo.config?.params?.vectors?.size
54-
5576
if (existingVectorSize === this.vectorSize) {
56-
// Collection exists and has correct vector size
57-
created = false
77+
created = false // Exists and correct
5878
} else {
59-
// Collection exists but has wrong vector size - recreate it
79+
// Exists but wrong vector size, recreate
6080
console.warn(
6181
`[QdrantVectorStore] Collection ${this.collectionName} exists with vector size ${existingVectorSize}, but expected ${this.vectorSize}. Recreating collection.`,
6282
)
63-
await this.client.deleteCollection(this.collectionName)
64-
await this.client.createCollection(this.collectionName, {
65-
vectors: {
66-
size: this.vectorSize,
67-
distance: this.DISTANCE_METRIC,
68-
},
69-
})
70-
created = true
71-
}
72-
} catch (error: any) {
73-
// Check if this is a "Not Found" error (collection doesn't exist)
74-
if (error?.response?.status === 404) {
75-
// Collection doesn't exist - create it
83+
await this.client.deleteCollection(this.collectionName) // Known to exist
7684
await this.client.createCollection(this.collectionName, {
7785
vectors: {
7886
size: this.vectorSize,
7987
distance: this.DISTANCE_METRIC,
8088
},
8189
})
8290
created = true
83-
} else {
84-
// Other error - log and re-throw
85-
console.error(`[QdrantVectorStore] Error checking collection ${this.collectionName}:`, error)
86-
throw error
8791
}
8892
}
8993

90-
// Create payload indexes for pathSegments up to depth 5
94+
// Create payload indexes
9195
for (let i = 0; i <= 4; i++) {
9296
try {
9397
await this.client.createPayloadIndex(this.collectionName, {
9498
field_name: `pathSegments.${i}`,
9599
field_schema: "keyword",
96100
})
97-
} catch (indexError) {
98-
console.warn(
99-
`[QdrantVectorStore] Could not create payload index for pathSegments.${i} on ${this.collectionName}. It might already exist or there was an issue.`,
100-
indexError,
101-
)
101+
} catch (indexError: any) {
102+
const errorMessage = (indexError?.message || "").toLowerCase()
103+
if (!errorMessage.includes("already exists")) {
104+
console.warn(
105+
`[QdrantVectorStore] Could not create payload index for pathSegments.${i} on ${this.collectionName}. Details:`,
106+
indexError?.message || indexError,
107+
)
108+
}
102109
}
103110
}
104-
105111
return created
106-
} catch (error) {
107-
console.error("Failed to initialize Qdrant collection:", error)
112+
} catch (error: any) {
113+
console.error(
114+
`[QdrantVectorStore] Failed to initialize Qdrant collection "${this.collectionName}":`,
115+
error?.message || error,
116+
)
108117
throw error
109118
}
110119
}
@@ -295,16 +304,7 @@ export class QdrantVectorStore implements IVectorStore {
295304
* @returns Promise resolving to boolean indicating if the collection exists
296305
*/
297306
async collectionExists(): Promise<boolean> {
298-
try {
299-
// Prefer direct API call if supported
300-
await this.client.getCollection(this.collectionName)
301-
return true
302-
} catch (error: any) {
303-
if (error?.response?.status === 404) {
304-
return false
305-
}
306-
console.error("Error checking collection existence:", error)
307-
return false
308-
}
307+
const collectionInfo = await this.getCollectionInfo()
308+
return collectionInfo !== null
309309
}
310310
}

0 commit comments

Comments
 (0)