mastra-ai/mastra · error · Error

expectedVersion is only valid for an existing node.

Error message

expectedVersion is only valid for an existing node.

What it means

The node upsert tool uses expectedVersion for optimistic concurrency on existing nodes. If the (name, scope) does not resolve to an existing node, the call becomes a create, and expectedVersion is meaningless there — the library rejects the combination instead of ignoring it. This protects callers from thinking they are updating a node that actually does not exist yet.

Source

Thrown at packages/memory/src/processors/observational-memory/subconscious/knowledge-write-tools.ts:254

          kind?: string;
          content: string;
          scope?: KnowledgeScopeLevel;
          expectedVersion?: number;
        };
        const trimmedName = value.name.trim();
        const reservedName = trimmedName.toLowerCase();
        const name = reservedName === 'capture-guidance' ? reservedName : trimmedName;
        if (reservedName === 'capture-guidance' && value.content.length > MAX_GUIDANCE_LENGTH) {
          throw new Error(`capture-guidance is limited to ${MAX_GUIDANCE_LENGTH} characters.`);
        }
        const store = await getStore(memory);
        const scope = resolveWriteScope(options, value.scope);
        const resolvedNode = await store.resolveNode({ name, scope });
        const existing =
          resolvedNode && knowledgeScopeKey(resolvedNode.scope) === knowledgeScopeKey(scope) ? resolvedNode : null;
        if (!existing) {
          if (value.expectedVersion !== undefined)
            throw new Error('expectedVersion is only valid for an existing node.');
          return store.createNode({
            name,
            kind: value.kind ?? 'document',
            content: value.content,
            scope,
            resolutionScope: options.scope,
          });
        }
        if (value.expectedVersion === undefined) throw new Error('Updating node content requires expectedVersion.');
        return store.updateNode({
          id: existing.id,
          version: value.expectedVersion,
          kind: value.kind,
          content: value.content,
          resolutionScope: options.scope,
        });
      },
    }),

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Omit expectedVersion to create the node, or first create the node then update with expectedVersion
  2. Verify the node exists with store.resolveNode({ name, scope }) and that the scope matches the node's scope key
  3. Correct the node name or scope level so it resolves to the existing node

Example fix

// before
await tool.execute({ name: 'typo-name', content, expectedVersion: 2 });
// after
const resolved = await store.resolveNode({ name: 'node-name', scope });
if (resolved) await tool.execute({ name: 'node-name', content, expectedVersion: resolved.version });
else await tool.execute({ name: 'node-name', content });
Defensive patterns

Strategy: validation

Validate before calling

const resolved = await store.resolveNode({ name, scope });
if (!resolved && expectedVersion !== undefined) {
  delete input.expectedVersion; // create path
}

Try / catch

try {
  await tool.execute(input);
} catch (e) {
  if (e instanceof Error && e.message.includes('expectedVersion is only valid for an existing node')) {
    const { expectedVersion, ...createInput } = input;
    await tool.execute(createInput); // retry as create
  } else throw e;
}

Prevention

When it happens

Trigger: Passing expectedVersion with a name that has no node in the target scope — e.g. a typo'd node name, wrong scope level, or a node that was deleted or merged so resolveNode no longer matches within the same scope key.

Common situations: First-time writes to a node assumed to exist; scope mismatch so resolveNode looks in a different scope than where the node lives; concurrent merge removed the node between planning and execution.

Related errors


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