mastra-ai/mastra · error

Record is not a pin: ${recordId}

Error message

Record is not a pin: ${recordId}

What it means

requirePin also verifies that the resolved record actually lives on the reserved pinned-knowledge node (record.node must equal the node id resolved for the configured scope). A record id that points at ordinary knowledge — e.g. a learned or curated record — is rejected with this error. This prevents callers from unpinning or mutating non-pin knowledge through the pin tools.

Source

Thrown at packages/memory/src/processors/observational-memory/subconscious/pinned.ts:179

    defaultScope: expandKnowledgeScope(options.scope, options.defaultScope),
  });
}

async function getStore(memory: PinnedMemory): Promise<KnowledgeStorage> {
  const store = await memory.storage.getStore('knowledge');
  if (!store) throw new Error('Pinned knowledge requires a configured knowledge storage domain.');
  return store;
}

async function requirePin(
  store: KnowledgeStorage,
  recordId: string,
  options: PinnedToolsOptions,
): Promise<KnowledgeRecord> {
  const record = await store.getKnowledge({ id: recordId, includeDeleted: false });
  if (!record) throw new Error(`Pin not found: ${recordId}`);
  const nodeId = await resolvePinnedNodeId(store, options.scope);
  if (!nodeId || record.node !== nodeId) throw new Error(`Record is not a pin: ${recordId}`);
  if (!isKnowledgeScopeVisible(record.scope, options.scope)) throw new Error('Pin is outside the visible scope.');
  return record;
}

/**
 * Pin lifecycle tools. Pin appends a record on the reserved node; unpin soft-deletes it
 * (auditable, restorable); edit is remove plus append because knowledge records are immutable,
 * so an edited pin carries a new record id.
 */
export function createPinnedTools(
  memory: PinnedMemory,
  options: PinnedToolsOptions,
): Record<string, ToolAction<any, any, any>> {
  return {
    knowledge_pin: createTool({
      id: 'knowledge_pin',
      description:
        'Pin knowledge that must stay in context every turn without being asked for. Pins cost context permanently; pin only what is unconditionally relevant.',

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Use only ids returned by the pin/list tool, not from general knowledge lookups
  2. Ensure the pinned tools' scope configuration matches the scope where the pins were created
  3. Look up the reserved pinned node and enumerate its records to get valid pin ids
  4. If the intent is to manage non-pin knowledge, use the general knowledge APIs, not pin tools

Example fix

// before: using a learned record id with the unpin tool
await unpinTool.execute({ recordId: learnedRecord.id });
// Error: Record is not a pin: kn_456
// after: use an id from the pin listing
const pins = await listPins(memory, { scope });
await unpinTool.execute({ recordId: pins[0].id });
Defensive patterns

Strategy: validation

Validate before calling

const record = await store.getKnowledge({ id: recordId, includeDeleted: false });
const nodeId = await resolvePinnedNodeId(store, scope);
if (!record || !nodeId || record.node !== nodeId) {
  throw new Error(`${recordId} is not a pin; use ids returned by the pin listing.`);
}

Type guard

function isPinOnReservedNode(record, pinnedNodeId) {
  return !!record && !!pinnedNodeId && record.node === pinnedNodeId;
}

Try / catch

try {
  await pinTool.execute({ recordId });
} catch (err) {
  if (err.message.startsWith('Record is not a pin')) {
    // fetch a valid pin id from the pin list; do not retry with the same id
  } else throw err;
}

Prevention

When it happens

Trigger: Passing a valid knowledge record id that belongs to a regular (non-reserved) node to a pin tool; calling pin tools with an id from the wrong scope so resolvePinnedNodeId resolves a different (or missing) reserved node.

Common situations: Agent grabbing an arbitrary knowledge id (from learned records) and attempting to unpin it; pin tools configured with a different scope than the one the pins were created under; mixing pinned and learner record ids in one client.

Related errors


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