{"record":{"id":"22489fcbbd029185","repo":"mastra-ai/mastra","slug":"batch-embedder-returned-no-embedding-for-input-tex","errorCode":null,"errorMessage":"Batch embedder returned no embedding for input text.","messagePattern":"Batch embedder returned no embedding for input text\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/core/src/workspace/search/search-engine.ts","lineNumber":687,"sourceCode":"      return 'bm25';\n    }\n\n    throw new Error('No search configuration available. Provide bm25 or vector config.');\n  }\n\n  /**\n   * Embed a single text, dispatching to the batch path with a one-element array\n   * when the configured embedder is batch-capable.\n   */\n  async #embedOne(text: string): Promise<number[]> {\n    if (!this.#vectorConfig) {\n      throw new Error('Vector configuration is required to embed text.');\n    }\n    const { embedder } = this.#vectorConfig;\n    if (isBatchEmbedder(embedder)) {\n      const [embedding] = await embedder([text]);\n      if (!embedding) {\n        throw new Error('Batch embedder returned no embedding for input text.');\n      }\n      return embedding;\n    }\n    return embedder(text);\n  }\n\n  /**\n   * Embed many texts. Uses a single batched call (chunked by `maxBatchSize`)\n   * when the embedder is batch-capable; otherwise falls back to parallel\n   * single-text calls.\n   */\n  async #embedAll(texts: string[]): Promise<number[][]> {\n    if (!this.#vectorConfig) {\n      throw new Error('Vector configuration is required to embed texts.');\n    }\n    if (texts.length === 0) return [];\n\n    const { embedder } = this.#vectorConfig;","sourceCodeStart":669,"sourceCodeEnd":705,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/workspace/search/search-engine.ts#L669-L705","documentation":"The configured embedder is a batch-capable embedder (branded with `batch: true`), and `#embedOne` dispatched the single text as a one-element array, but the returned embeddings array was empty — no embedding came back for the input. This indicates a misbehaving embedder implementation rather than a configuration problem.","triggerScenarios":"A `BatchEmbedder` whose implementation returns an array shorter than its input (e.g. `embedMany` result destructured incorrectly, empty array returned for empty/filtered input, provider dropping a text) reached via `embedding(text)` or `queryEmbedding(text)`.","commonSituations":"Custom embedder wrappers that filter out blank strings and return fewer results; a provider returning zero embeddings on API error without throwing; hand-rolled `Object.assign(fn, { batch: true })` where `fn` doesn't preserve input order/count.","solutions":["Fix the batch embedder implementation so it always returns exactly one embedding per input text, in order (verify the `embedMany` result: `return embeddings`, not a nested/destructured value).","Add an assertion in your embedder: throw if `embeddings.length !== texts.length`.","If the provider can silently drop inputs, fall back to a single-text embedder (omit the `batch: true` brand) so each call gets one result."],"exampleFix":"// before — drops texts, returns fewer embeddings\nconst embedder: BatchEmbedder = Object.assign(\n  async (texts) => {\n    const { embeddings } = await embedMany({ model, values: texts.filter(Boolean) });\n    return embeddings;\n  },\n  { batch: true as const },\n);\n\n// after — 1:1 with input, validated\nconst embedder: BatchEmbedder = Object.assign(\n  async (texts) => {\n    const { embeddings } = await embedMany({ model, values: texts });\n    if (embeddings.length !== texts.length) {\n      throw new Error('Embedding count mismatch');\n    }\n    return embeddings;\n  },\n  { batch: true as const },\n);","handlingStrategy":"type-guard","validationCode":"function assertValidBatchEmbedder(e: Embedder): asserts e is BatchEmbedder {\n  if (!isBatchEmbedder(e)) return;\n  // smoke-test in dev: batch embedder must return 1:1 results\n}\n// at construction:\nconst probe = await embedder(['ping']);\nif (probe.length !== 1) throw new Error('Batch embedder violates 1:1 contract');","typeGuard":"function isWellFormedBatchEmbedder(e: Embedder): e is BatchEmbedder {\n  return isBatchEmbedder(e) && typeof e === 'function';\n}","tryCatchPattern":"try {\n  const vec = await engine.queryEmbedding(text);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('Batch embedder returned no embedding')) {\n    // rebuild engine with a single-text embedder or fixed batch embedder\n  } else {\n    throw e;\n  }\n}","preventionTips":["Validate custom batch embedders with a probe call at startup (1 input -> 1 output).","Never filter or reorder inputs inside a batch embedder; preserve input length and order.","Throw explicitly inside the embedder on provider errors instead of returning short arrays.","Add a length assertion (`embeddings.length === texts.length`) in the embedder wrapper."],"tags":["embeddings","batch-embedder","vector-search","contract-violation"],"backgroundTag":"embedder-returned-no-embedding","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}