Skip to content
This repository was archived by the owner on May 15, 2026. It is now read-only.

Commit f9debc6

Browse files
committed
fix: handle ByteString error in embedder validation flow
Add handling for ByteString conversion errors in the code index validation helpers. This error occurs when non-ASCII characters (e.g., Cyrillic) are present in the API key or base URL configuration, causing HTTP header encoding to fail. The fix: - Adds ByteString error detection in handleValidationError function - Returns a user-friendly localized error message from common namespace - Adds comprehensive test coverage for the new error handling Fixes #10973
1 parent 953c777 commit f9debc6

2 files changed

Lines changed: 128 additions & 2 deletions

File tree

src/services/code-index/shared/__tests__/validation-helpers.spec.ts

Lines changed: 121 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,21 @@
1-
import { sanitizeErrorMessage } from "../validation-helpers"
1+
import { sanitizeErrorMessage, handleValidationError } from "../validation-helpers"
2+
3+
vi.mock("../../../../i18n", () => ({
4+
t: (key: string) => {
5+
// Return the key itself for testing purposes
6+
const translations: Record<string, string> = {
7+
"common:errors.api.invalidKeyInvalidChars": "API key contains invalid characters.",
8+
"embeddings:validation.connectionFailed": "Connection failed",
9+
"embeddings:validation.invalidResponse": "Invalid response",
10+
"embeddings:validation.configurationError": "Configuration error",
11+
"embeddings:validation.authenticationFailed": "Authentication failed",
12+
"embeddings:validation.modelNotAvailable": "Model not available",
13+
"embeddings:validation.invalidEndpoint": "Invalid endpoint",
14+
"embeddings:validation.serviceUnavailable": "Service unavailable",
15+
}
16+
return translations[key] || key
17+
},
18+
}))
219

320
describe("sanitizeErrorMessage", () => {
421
it("should sanitize Unix-style file paths", () => {
@@ -90,3 +107,106 @@ describe("sanitizeErrorMessage", () => {
90107
expect(sanitizeErrorMessage(input)).toBe(expected)
91108
})
92109
})
110+
111+
describe("handleValidationError", () => {
112+
it("should handle ByteString conversion error with user-friendly message", () => {
113+
const error = new Error(
114+
"Cannot convert argument to a ByteString because the character at index 8 has a value of 1040 which is greater than 255",
115+
)
116+
const result = handleValidationError(error, "openai-compatible")
117+
expect(result.valid).toBe(false)
118+
expect(result.error).toBe("API key contains invalid characters.")
119+
})
120+
121+
it("should handle ByteString error with various character indices", () => {
122+
const error = new Error(
123+
"Cannot convert argument to a ByteString because the character at index 0 has a value of 256",
124+
)
125+
const result = handleValidationError(error, "openai")
126+
expect(result.valid).toBe(false)
127+
expect(result.error).toBe("API key contains invalid characters.")
128+
})
129+
130+
it("should handle connection refused errors", () => {
131+
const error = new Error("ECONNREFUSED 127.0.0.1:11434")
132+
const result = handleValidationError(error, "ollama")
133+
expect(result.valid).toBe(false)
134+
expect(result.error).toBe("Connection failed")
135+
})
136+
137+
it("should handle ENOTFOUND errors", () => {
138+
const error = new Error("getaddrinfo ENOTFOUND api.example.com")
139+
const result = handleValidationError(error, "openai")
140+
expect(result.valid).toBe(false)
141+
expect(result.error).toBe("Connection failed")
142+
})
143+
144+
it("should handle timeout errors", () => {
145+
const error = new Error("ETIMEDOUT")
146+
const result = handleValidationError(error, "openai")
147+
expect(result.valid).toBe(false)
148+
expect(result.error).toBe("Connection failed")
149+
})
150+
151+
it("should handle invalid JSON response errors", () => {
152+
const error = new Error("Failed to parse response JSON")
153+
const result = handleValidationError(error, "openai")
154+
expect(result.valid).toBe(false)
155+
expect(result.error).toBe("Invalid response")
156+
})
157+
158+
it("should preserve generic error messages", () => {
159+
const error = new Error("Something went wrong")
160+
const result = handleValidationError(error, "openai")
161+
expect(result.valid).toBe(false)
162+
expect(result.error).toBe("Something went wrong")
163+
})
164+
165+
it("should handle errors with status codes", () => {
166+
const error = { status: 401, message: "Unauthorized" }
167+
const result = handleValidationError(error, "openai")
168+
expect(result.valid).toBe(false)
169+
expect(result.error).toBe("Authentication failed")
170+
})
171+
172+
it("should handle 404 errors for openai provider", () => {
173+
const error = { status: 404, message: "Not Found" }
174+
const result = handleValidationError(error, "openai")
175+
expect(result.valid).toBe(false)
176+
expect(result.error).toBe("Model not available")
177+
})
178+
179+
it("should handle 404 errors for non-openai providers", () => {
180+
const error = { status: 404, message: "Not Found" }
181+
const result = handleValidationError(error, "ollama")
182+
expect(result.valid).toBe(false)
183+
expect(result.error).toBe("Invalid endpoint")
184+
})
185+
186+
it("should handle rate limit errors", () => {
187+
const error = { status: 429, message: "Too Many Requests" }
188+
const result = handleValidationError(error, "openai")
189+
expect(result.valid).toBe(false)
190+
expect(result.error).toBe("Service unavailable")
191+
})
192+
193+
it("should allow custom handlers to override standard handling", () => {
194+
const error = new Error("Custom error")
195+
const customHandlers = {
196+
beforeStandardHandling: () => ({ valid: false, error: "Custom handled error" }),
197+
}
198+
const result = handleValidationError(error, "openai", customHandlers)
199+
expect(result.valid).toBe(false)
200+
expect(result.error).toBe("Custom handled error")
201+
})
202+
203+
it("should continue with standard handling if custom handler returns undefined", () => {
204+
const error = new Error("ECONNREFUSED")
205+
const customHandlers = {
206+
beforeStandardHandling: () => undefined,
207+
}
208+
const result = handleValidationError(error, "openai", customHandlers)
209+
expect(result.valid).toBe(false)
210+
expect(result.error).toBe("Connection failed")
211+
})
212+
})

src/services/code-index/shared/validation-helpers.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,14 @@ export function handleValidationError(
170170
return { valid: false, error: statusError }
171171
}
172172

173-
// Check for connection errors
173+
// Check for connection errors and special error cases
174174
if (errorMessage) {
175+
// ByteString conversion error indicates invalid characters in API key or base URL
176+
// This happens when non-ASCII characters (e.g., Cyrillic) are present in configuration
177+
if (errorMessage.includes("Cannot convert argument to a ByteString")) {
178+
return { valid: false, error: t("common:errors.api.invalidKeyInvalidChars") }
179+
}
180+
175181
if (
176182
errorMessage.includes("ENOTFOUND") ||
177183
errorMessage.includes("ECONNREFUSED") ||

0 commit comments

Comments
 (0)