{"record":{"id":"04434e0efdcef1b3","repo":"n8n-io/n8n","slug":"document-at-index-index-has-empty-content-not","errorCode":null,"errorMessage":"Document at index ${index} has empty content — nothing to embed.","messagePattern":"Document at index (.+?) has empty content — nothing to embed\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@n8n/agents/src/sdk/vector-store.ts","lineNumber":94,"sourceCode":"\t\t\tassertValidTopK(opts.topK);\n\t\t}\n\t\tconst { backend, embeddingModel } = this.ensureBuilt();\n\t\tconst { embed } = await import('ai');\n\t\tconst { embedding } = await embed({ model: embeddingModel, value: query });\n\t\tconst filter = this.resolveFilter(opts?.filter);\n\t\treturn await backend.query(embedding, {\n\t\t\ttopK: opts?.topK ?? this.topKValue,\n\t\t\t...(filter ? { filter } : {}),\n\t\t});\n\t}\n\n\t/** Embed and upsert documents into the store. Returns the ids used (generated when not provided). */\n\tasync addDocuments(docs: VectorDocument[]): Promise<string[]> {\n\t\tif (docs.length === 0) return [];\n\n\t\tdocs.forEach((doc, index) => {\n\t\t\tif (typeof doc.content !== 'string' || doc.content.trim() === '') {\n\t\t\t\tthrow new Error(`Document at index ${index} has empty content — nothing to embed.`);\n\t\t\t}\n\t\t});\n\n\t\tconst { backend, embeddingModel } = this.ensureBuilt();\n\t\tconst ids = docs.map((doc) => doc.id ?? crypto.randomUUID());\n\t\tconst { embedMany } = await import('ai');\n\t\tconst { embeddings } = await embedMany({\n\t\t\tmodel: embeddingModel,\n\t\t\tvalues: docs.map((doc) => doc.content),\n\t\t});\n\t\tawait backend.upsert(\n\t\t\tdocs.map((doc, index) => ({\n\t\t\t\tid: ids[index],\n\t\t\t\tvector: embeddings[index],\n\t\t\t\tcontent: doc.content,\n\t\t\t\tmetadata: doc.metadata ?? {},\n\t\t\t})),\n\t\t);","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/agents/src/sdk/vector-store.ts#L76-L112","documentation":"VectorStore.addDocuments() pre-validates every document's content before embedding: content must be a non-empty trimmed string. Embedding empty or whitespace-only content wastes an embedding API call and pollutes the vector index with garbage vectors that match everything and nothing. The check is per-document with the offending index in the message.","triggerScenarios":"Calling store.addDocuments([{ content: '', metadata: {...} }]) or any document whose content is whitespace ('   '), null, undefined, or a non-string. The forEach throws on the first offending index before any embedding work begins.","commonSituations":"Bulk-ingesting from a source with missing/blank fields (e.g. empty page bodies, filtered-out sections); content that is null after a parsing step; whitespace from stripped HTML; documents built from optional fields that were absent.","solutions":["Filter documents before ingest: docs.filter(d => typeof d.content === 'string' && d.content.trim().length > 0).","Default missing content to a meaningful placeholder or skip the document rather than embedding emptiness.","Validate at the source parser so blank content never reaches addDocuments."],"exampleFix":"// before\nstore.addDocuments(pages.map(p => ({ content: p.body, metadata: { url: p.url } })));\n// throws if any page.body is '' or whitespace\n\n// after — filter empties first\nstore.addDocuments(\n  pages\n    .filter(p => typeof p.body === 'string' && p.body.trim().length > 0)\n    .map(p => ({ content: p.body, metadata: { url: p.url } })),\n);","handlingStrategy":"validation","validationCode":"function cleanDocs(docs: VectorDocument[]) {\n  return docs.filter(\n    d => typeof d.content === 'string' && d.content.trim().length > 0,\n  );\n}","typeGuard":"function hasNonEmptyContent(doc: { content: unknown }): doc is { content: string } {\n  return typeof doc.content === 'string' && doc.content.trim().length > 0;\n}","tryCatchPattern":"try {\n  await store.addDocuments(docs);\n} catch (err) {\n  if (err instanceof Error && err.message.includes('empty content')) {\n    const cleaned = docs.filter(d => typeof d.content === 'string' && d.content.trim().length > 0);\n    if (cleaned.length) await store.addDocuments(cleaned);\n  } else throw err;\n}","preventionTips":["Filter blanks at the parser/ingest layer so empty content never reaches addDocuments.","Add a data-quality check on source datasets before bulk ingest.","Log skipped documents during cleanup so silent data loss is visible."],"tags":["vector-store","add-documents","validation","data-quality"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}