mastra-ai/mastra · error

Node must have an embedding

Error message

Node must have an embedding

What it means

GraphRAG's addNode requires every node to carry an embedding vector, since similarity edges and graph traversal are computed from embeddings. If node.embedding is falsy (undefined/null/empty), the node cannot participate and the method throws. It is a structural precondition of building the graph.

Source

Thrown at packages/rag/src/graph-rag/index.ts:69

const GRAPH_RAG_SNAPSHOT_VERSION = 1;

export class GraphRAG {
  private nodes: Map<string, GraphNode>;
  private edges: GraphEdge[];
  private dimension: number;
  private threshold: number;

  constructor(dimension: number = 1536, threshold: number = 0.7) {
    this.nodes = new Map();
    this.edges = [];
    this.dimension = dimension;
    this.threshold = threshold;
  }

  // Add a node to the graph
  addNode(node: GraphNode): void {
    if (!node.embedding) {
      throw new Error('Node must have an embedding');
    }
    if (node.embedding.length !== this.dimension) {
      throw new Error(`Embedding dimension must be ${this.dimension}`);
    }
    this.nodes.set(node.id, node);
  }

  // Add an edge between two nodes
  addEdge(edge: GraphEdge): void {
    if (!this.nodes.has(edge.source) || !this.nodes.has(edge.target)) {
      throw new Error('Both source and target nodes must exist');
    }
    this.edges.push(edge);
    // Add reverse edge
    this.edges.push({
      source: edge.target,
      target: edge.source,
      weight: edge.weight,

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Embed all documents first with embedMany (or via MDocument.embed) and attach results: { ...doc, embedding: embeddings[i] }.
  2. Filter out nodes lacking embeddings before calling addNode/createGraph.
  3. Check your embedding step for silent failures (empty response arrays, rate-limit partials).
  4. If a node legitimately has no embedding, exclude it from the graph rather than passing null.

Example fix

// before
nodes.forEach(n => graph.addNode({ id: n.id, content: n.text }));
// after
const { embeddings } = await embedMany({ model, values: nodes.map(n => n.text) });
nodes.forEach((n, i) => graph.addNode({ id: n.id, content: n.text, embedding: embeddings[i] }));
Defensive patterns

Strategy: validation

Validate before calling

function assertEmbeddings(nodes: { id: string; embedding?: number[] }[]): void {
  const missing = nodes.filter(n => !n.embedding || n.embedding.length === 0);
  if (missing.length) throw new Error(`Nodes missing embeddings: ${missing.map(n => n.id).join(', ')}`);
}

Type guard

function hasEmbedding(n: GraphNode): n is GraphNode & { embedding: number[] } {
  return Array.isArray(n.embedding) && n.embedding.length > 0;
}

Try / catch

try {
  nodes.forEach(n => graph.addNode(n));
} catch (e) {
  if ((e as Error).message === 'Node must have an embedding') {
    console.error('A node reached addNode without an embedding; re-run the embed step');
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling graph.addNode(node) or createGraph({ nodes }) where some nodes were constructed without an embedding field, or where embedding generation (embedMany/upsert step) silently failed or was skipped.

Common situations: Mixing documents that were embedded with raw records loaded from a database; a failed embed() step returning partial results; hand-building GraphNode objects for tests without embeddings; deserializing old/partial data (though deserialize filters).

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/022ac40a39f08617. Report an issue: GitHub.