{"record":{"id":"77a1e4e3109d693d","repo":"chatboxai/chatbox","slug":"embedding-batch-failed-expected-batchtexts-leng","errorCode":null,"errorMessage":"Embedding batch failed: expected ${batchTexts.length}, got ${embeddingResult.embeddings?.length || 0}","messagePattern":"Embedding batch failed: expected (.+?), got (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"src/main/knowledge-base/file-loaders.ts","lineNumber":202,"sourceCode":"      }\n\n      const batchChunks = remainingChunks.slice(i, i + BATCH_SIZE)\n      const batchTexts = batchChunks.map((chunk: any) => `filename: ${fileMeta.filename}\\nchunk:\\n${chunk.text}`)\n\n      const batchNumber = Math.floor(i / BATCH_SIZE) + 1\n      const totalBatches = Math.ceil(remainingChunks.length / BATCH_SIZE)\n      log.debug(`[FILE] Processing batch ${batchNumber}/${totalBatches}, chunks: ${batchTexts.length}`)\n\n      // Generate embeddings for this batch\n      const embeddingResult = await embedMany({\n        model: embeddingInstance,\n        values: batchTexts,\n        // Embeddings are billable; network-error retries could double-charge.\n        maxRetries: 0,\n      })\n\n      if (!embeddingResult.embeddings || embeddingResult.embeddings.length !== batchTexts.length) {\n        throw new Error(\n          `Embedding batch failed: expected ${batchTexts.length}, got ${embeddingResult.embeddings?.length || 0}`\n        )\n      }\n\n      // Store vectors for this batch\n      log.debug(`[FILE] Storing batch ${batchNumber}/${totalBatches} to vector store`)\n      await vectorStore.upsert({\n        indexName,\n        vectors: embeddingResult.embeddings,\n        metadata: batchChunks.map((chunk: any, chunkIndex: number) => ({\n          text: chunk.text,\n          fileId: fileMeta.fileId,\n          filename: fileMeta.filename,\n          mimeType: fileMeta.mimeType,\n          chunkIndex: currentChunkCount + i + chunkIndex, // Use absolute chunk index\n        })),\n      })\n","sourceCodeStart":184,"sourceCodeEnd":220,"githubUrl":"https://github.com/chatboxai/chatbox/blob/81571269addb6bafb589a920b2883f1e1e084fd1/src/main/knowledge-base/file-loaders.ts#L184-L220","documentation":"Thrown at the top of Gemini.paint() (built-in Google Gemini provider) when `isGeminiImageModel(this.options.model.modelId)` is false. Same guard as CustomGemini.paint(): the model id must contain both 'gemini' and 'image'. Fires before any network call, so it is a capability check — paint() was invoked on a text-only Gemini model.","triggerScenarios":"User opens image generation while a text Gemini model (e.g. `gemini-2.5-pro`, `gemini-2.0-flash`) is the active session model; a stored session restored a non-image model and the paint action is invoked automatically; the model nickname differs from its id and the UI dispatched paint() based on display name rather than id-based capability check.","commonSituations":"Newly added Gemini text model selected by default after a refresh; user expects all Gemini models to generate images; image model id changed in a Google API revision and the new id lacks the 'image' substring; the UI does not pre-check capability before showing the paint affordance.","solutions":["Gate the image-generation UI on `isGeminiImageModel(modelId)` and disable the paint button for non-matching models.","Switch to a recognised Gemini image model (`gemini-2.0-flash-exp-image-generation`, `gemini-2.5-flash-image-preview`).","Keep image-models.ts in sync if Google ships image models whose id does not match the `gemini`+`image` rule.","If you call paint() programmatically, assert the capability first and surface a typed error to the caller rather than letting ApiError propagate."],"exampleFix":"// before\nconst images = await gemini.paint({ prompt, num: 1 })  // throws on text models\n\n// after\nif (!isGeminiImageModel(gemini.options.model.modelId)) {\n  throw new Error(`Model ${gemini.options.model.modelId} cannot generate images`)\n}\nconst images = await gemini.paint({ prompt, num: 1 })","handlingStrategy":"validation","validationCode":"function canPaint(modelId: string): boolean {\n  return modelId.includes('gemini') && modelId.includes('image')\n}\nif (!canPaint(session.modelId)) disablePaintUI()","typeGuard":"import { isGeminiImageModel } from '../image-models'\nfunction assertImageCapable(modelId: string): void {\n  if (!isGeminiImageModel(modelId)) throw new Error(`Model ${modelId} cannot generate images`)\n}","tryCatchPattern":"try { await gemini.paint({ prompt, num: 1 }) }\ncatch (e) {\n  if (e instanceof ApiError && e.message.includes('does not support image generation')) {\n    showWarning('Select a Gemini image model to generate images')\n    return []\n  }\n  throw e\n}","preventionTips":["Gate the paint UI on isGeminiImageModel(selectedModelId).","Keep image-models.ts in sync with new Gemini image model ids.","Validate capability by model id, not display name."],"tags":["gemini","image-generation","validation","model-capability","ui"],"backgroundTag":null,"analyzedSha":"81571269addb6bafb589a920b2883f1e1e084fd1","analyzedAt":"2026-08-12T21:51:44.981Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}