n8n-io/n8n · error · Error
Document at index ${index} has empty content — nothing to em
Error message
Document at index ${index} has empty content — nothing to embed. What it means
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.
Source
Thrown at packages/@n8n/agents/src/sdk/vector-store.ts:94
assertValidTopK(opts.topK);
}
const { backend, embeddingModel } = this.ensureBuilt();
const { embed } = await import('ai');
const { embedding } = await embed({ model: embeddingModel, value: query });
const filter = this.resolveFilter(opts?.filter);
return await backend.query(embedding, {
topK: opts?.topK ?? this.topKValue,
...(filter ? { filter } : {}),
});
}
/** Embed and upsert documents into the store. Returns the ids used (generated when not provided). */
async addDocuments(docs: VectorDocument[]): Promise<string[]> {
if (docs.length === 0) return [];
docs.forEach((doc, index) => {
if (typeof doc.content !== 'string' || doc.content.trim() === '') {
throw new Error(`Document at index ${index} has empty content — nothing to embed.`);
}
});
const { backend, embeddingModel } = this.ensureBuilt();
const ids = docs.map((doc) => doc.id ?? crypto.randomUUID());
const { embedMany } = await import('ai');
const { embeddings } = await embedMany({
model: embeddingModel,
values: docs.map((doc) => doc.content),
});
await backend.upsert(
docs.map((doc, index) => ({
id: ids[index],
vector: embeddings[index],
content: doc.content,
metadata: doc.metadata ?? {},
})),
);View on GitHub (pinned to 5ac6606e81)
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.
Example fix
// before
store.addDocuments(pages.map(p => ({ content: p.body, metadata: { url: p.url } })));
// throws if any page.body is '' or whitespace
// after — filter empties first
store.addDocuments(
pages
.filter(p => typeof p.body === 'string' && p.body.trim().length > 0)
.map(p => ({ content: p.body, metadata: { url: p.url } })),
); Defensive patterns
Strategy: validation
Validate before calling
function cleanDocs(docs: VectorDocument[]) {
return docs.filter(
d => typeof d.content === 'string' && d.content.trim().length > 0,
);
} Type guard
function hasNonEmptyContent(doc: { content: unknown }): doc is { content: string } {
return typeof doc.content === 'string' && doc.content.trim().length > 0;
} Try / catch
try {
await store.addDocuments(docs);
} catch (err) {
if (err instanceof Error && err.message.includes('empty content')) {
const cleaned = docs.filter(d => typeof d.content === 'string' && d.content.trim().length > 0);
if (cleaned.length) await store.addDocuments(cleaned);
} else throw err;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Invalid filter operator "${operator}" for key "${key}". Supp
- Filter operator "${operator}" on key "${key}" requires a non
- Filter operator "${operator}" on key "${key}" requires array
- Filter operator "${operator}" on key "${key}" requires a str
- filterableKeys must contain at least one key
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/04434e0efdcef1b3.
Report an issue: GitHub.