mastra-ai/mastra · error

Pin not found: ${recordId}

Error message

Pin not found: ${recordId}

What it means

requirePin loads a knowledge record by id (excluding soft-deleted records) and throws when no record with that id exists. It is the existence half of pin validation — a subsequent check then verifies the record actually belongs to the reserved pinned node. The error surfaces when tools receive an id that never existed or that has been unpinned (soft-deleted).

Source

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

    metadata,
    resolutionScope: options.scope,
    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',

View on GitHub (pinned to 75dd419e61)

Solutions

  1. List the current pins first and use a returned record id, don't guess
  2. Re-check whether the record was already unpinned (soft-deleted records are not returned)
  3. Verify the recordId string for typos or truncation
  4. If ids come from the model, validate them against the pin list before invoking the tool

Example fix

// before: unpinning with a stale id
await unpinTool.execute({ recordId: 'kn_123' }); // already unpinned
// Error: Pin not found: kn_123
// after: resolve a live pin id first
const pins = await listPins(memory);
await unpinTool.execute({ recordId: pins[0].id });
Defensive patterns

Strategy: try-catch

Validate before calling

const store = await memory.storage.getStore('knowledge');
const record = store ? await store.getKnowledge({ id: recordId, includeDeleted: false }) : undefined;
if (!record) throw new Error(`Refusing to operate on missing/soft-deleted record: ${recordId}`);

Type guard

function isLivePin(record) {
  return !!record && record.deletedAt == null;
}

Try / catch

try {
  await unpinTool.execute({ recordId });
} catch (err) {
  if (err.message.startsWith('Pin not found')) {
    // already unpinned or bad id: refresh the pin list instead of retrying blindly
  } else throw err;
}

Prevention

When it happens

Trigger: Calling a pinned tool (e.g. unpin/replace) with a recordId that was soft-deleted (unpinned earlier), was never created, or contains a typo/hallucinated id from the model.

Common situations: LLM agent inventing ids to unpin; double-unpinning the same record; ids from a different scope/resource that are not present in this store view; stale UI/client cache after an unpin.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


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