{"record":{"id":"14baee2092c4d365","repo":"ruvnet/ruflo","slug":"embedbatch-expects-an-array-of-strings","errorCode":null,"errorMessage":"embedBatch() expects an array of strings","messagePattern":"embedBatch\\(\\) expects an array of strings","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/embeddings/src/rvf-embedding-service.ts","lineNumber":214,"sourceCode":"\n    // Store in caches\n    this.cache.set(text, normalized);\n    if (this.persistentCache) {\n      await this.persistentCache.set(text, normalized);\n    }\n\n    const latencyMs = performance.now() - startTime;\n    this.emitEvent({ type: 'embed_complete', text, latencyMs });\n\n    return { embedding: normalized, latencyMs };\n  }\n\n  /**\n   * Generate embeddings for multiple text strings.\n   */\n  async embedBatch(texts: string[]): Promise<BatchEmbeddingResult> {\n    if (!Array.isArray(texts)) {\n      throw new Error('embedBatch() expects an array of strings');\n    }\n\n    this.emitEvent({ type: 'batch_start', count: texts.length });\n    const startTime = performance.now();\n\n    const embeddings: Float32Array[] = [];\n    let cacheHits = 0;\n\n    for (const text of texts) {\n      const cached = this.cache.get(text);\n      if (cached) {\n        embeddings.push(cached);\n        cacheHits++;\n        this.emitEvent({ type: 'cache_hit', text });\n        continue;\n      }\n\n      // Check persistent cache","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/embeddings/src/rvf-embedding-service.ts#L196-L232","documentation":"RvfEmbeddingService.embedBatch() generates embeddings for a list of texts and refuses to run unless the argument is an array. The guard fires before any embedding work or cache lookups, so nothing is partially processed. It exists because the method immediately iterates `texts` in a for-of loop and caches per string, which would misbehave on a bare string or undefined.","triggerScenarios":"Calling `embedBatch('some text')` with a single string instead of an array; passing `undefined` because an optional variable was never set; passing a Set, Map values iterator, or generator instead of a real array (Array.isArray is false for iterables).","commonSituations":"Migrating code from the single-string `embed()` API to `embedBatch()` and forgetting to wrap the text in brackets; passing a CSV string like 'a,b,c' expecting it to be split; defaulting a parameter to undefined when the caller omits it.","solutions":["Pass an array of strings: `await service.embedBatch(['hello world'])`","For a single text, call the single-item API `embed(text)` instead","Coerce iterables first: `embedBatch(Array.from(set))`","Split pre-joined strings yourself: `embedBatch(csv.split(','))`"],"exampleFix":"// before\nconst result = await service.embedBatch(longText);\n\n// after\nconst result = await service.embedBatch([longText]);\n// or for one document:\nconst single = await service.embed(longText);","handlingStrategy":"type-guard","validationCode":"if (!Array.isArray(texts)) {\n  texts = [texts]; // or throw your own clearer error\n}\nif (texts.some((t) => typeof t !== 'string')) {\n  throw new TypeError('texts must contain only strings');\n}","typeGuard":"const isStringArray = (v: unknown): v is string[] =>\n  Array.isArray(v) && v.every((t) => typeof t === 'string');","tryCatchPattern":null,"preventionTips":["Type the parameter as string[] in your own wrappers so the compiler catches it","Wrap single strings in brackets when migrating from embed() to embedBatch()","Convert iterables with Array.from() before passing them"],"tags":["input-validation","embeddings","argument-type","typescript"],"backgroundTag":"invalid-argument-value","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}