diff --git a/src/gateway/embeddings-http.test.ts b/src/gateway/embeddings-http.test.ts index 13eff394d17c..62fa4f59c242 100644 --- a/src/gateway/embeddings-http.test.ts +++ b/src/gateway/embeddings-http.test.ts @@ -434,6 +434,33 @@ describe("OpenAI-compatible embeddings HTTP API (e2e)", () => { await expectInvalidEmbeddingRequest(res); }); + it.each([ + { name: "an empty string", input: "" }, + { name: "an empty batch", input: [] }, + { name: "an empty batch entry", input: [""] }, + { name: "a mixed batch with an empty entry", input: ["valid", ""] }, + ])("rejects $name before creating an embedding provider", async ({ input }) => { + const providersCreatedBefore = createEmbeddingProviderMock.mock.calls.length; + const res = await postEmbeddings({ + model: "openclaw/default", + input, + }); + + await expectInvalidEmbeddingRequest(res, "`input` must contain at least one non-empty string."); + expect(createEmbeddingProviderMock).toHaveBeenCalledTimes(providersCreatedBefore); + }); + + it("preserves whitespace-only embedding input", async () => { + const input = " \t\n"; + const res = await postEmbeddings({ + model: "openclaw/default", + input, + }); + + await expectDefaultEmbeddingResponse(res); + expect(embedBatchMock.mock.calls.at(-1)?.[0]).toEqual([input]); + }); + it("ignores narrower declared scopes for shared-secret bearer auth", async () => { const res = await postEmbeddings( { diff --git a/src/gateway/embeddings-http.ts b/src/gateway/embeddings-http.ts index 8edc7ad730fd..2b949f03eec0 100644 --- a/src/gateway/embeddings-http.ts +++ b/src/gateway/embeddings-http.ts @@ -200,6 +200,9 @@ function encodeEmbeddingBase64(embedding: number[]): string { // Keep request limits local to the HTTP bridge; provider adapters may support // more, but this endpoint must protect gateway memory and request latency. function validateInputTexts(texts: string[]): string | undefined { + if (texts.length === 0 || texts.some((text) => text.length === 0)) { + return "`input` must contain at least one non-empty string."; + } if (texts.length > MAX_EMBEDDING_INPUTS) { return `Too many inputs (max ${MAX_EMBEDDING_INPUTS}).`; }