{"record":{"id":"09a7aba258c95d34","repo":"mastra-ai/mastra","slug":"record-is-not-a-pin-recordid","errorCode":null,"errorMessage":"Record is not a pin: ${recordId}","messagePattern":"Record is not a pin: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/memory/src/processors/observational-memory/subconscious/pinned.ts","lineNumber":179,"sourceCode":"    defaultScope: expandKnowledgeScope(options.scope, options.defaultScope),\n  });\n}\n\nasync function getStore(memory: PinnedMemory): Promise<KnowledgeStorage> {\n  const store = await memory.storage.getStore('knowledge');\n  if (!store) throw new Error('Pinned knowledge requires a configured knowledge storage domain.');\n  return store;\n}\n\nasync function requirePin(\n  store: KnowledgeStorage,\n  recordId: string,\n  options: PinnedToolsOptions,\n): Promise<KnowledgeRecord> {\n  const record = await store.getKnowledge({ id: recordId, includeDeleted: false });\n  if (!record) throw new Error(`Pin not found: ${recordId}`);\n  const nodeId = await resolvePinnedNodeId(store, options.scope);\n  if (!nodeId || record.node !== nodeId) throw new Error(`Record is not a pin: ${recordId}`);\n  if (!isKnowledgeScopeVisible(record.scope, options.scope)) throw new Error('Pin is outside the visible scope.');\n  return record;\n}\n\n/**\n * Pin lifecycle tools. Pin appends a record on the reserved node; unpin soft-deletes it\n * (auditable, restorable); edit is remove plus append because knowledge records are immutable,\n * so an edited pin carries a new record id.\n */\nexport function createPinnedTools(\n  memory: PinnedMemory,\n  options: PinnedToolsOptions,\n): Record<string, ToolAction<any, any, any>> {\n  return {\n    knowledge_pin: createTool({\n      id: 'knowledge_pin',\n      description:\n        'Pin knowledge that must stay in context every turn without being asked for. Pins cost context permanently; pin only what is unconditionally relevant.',","sourceCodeStart":161,"sourceCodeEnd":197,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/memory/src/processors/observational-memory/subconscious/pinned.ts#L161-L197","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Use only ids returned by the pin/list tool, not from general knowledge lookups","Ensure the pinned tools' scope configuration matches the scope where the pins were created","Look up the reserved pinned node and enumerate its records to get valid pin ids","If the intent is to manage non-pin knowledge, use the general knowledge APIs, not pin tools"],"exampleFix":"// before: using a learned record id with the unpin tool\nawait unpinTool.execute({ recordId: learnedRecord.id });\n// Error: Record is not a pin: kn_456\n// after: use an id from the pin listing\nconst pins = await listPins(memory, { scope });\nawait unpinTool.execute({ recordId: pins[0].id });","handlingStrategy":"validation","validationCode":"const record = await store.getKnowledge({ id: recordId, includeDeleted: false });\nconst nodeId = await resolvePinnedNodeId(store, scope);\nif (!record || !nodeId || record.node !== nodeId) {\n  throw new Error(`${recordId} is not a pin; use ids returned by the pin listing.`);\n}","typeGuard":"function isPinOnReservedNode(record, pinnedNodeId) {\n  return !!record && !!pinnedNodeId && record.node === pinnedNodeId;\n}","tryCatchPattern":"try {\n  await pinTool.execute({ recordId });\n} catch (err) {\n  if (err.message.startsWith('Record is not a pin')) {\n    // fetch a valid pin id from the pin list; do not retry with the same id\n  } else throw err;\n}","preventionTips":["Only pass ids obtained from pin-listing tools","Keep the pinned tools' scope identical to the scope used to create pins","Separate pin ids from learned/curated knowledge ids in agent state","When managing non-pin knowledge, use the general knowledge APIs"],"tags":["invalid-argument","knowledge-store","observational-memory"],"backgroundTag":"record-not-a-pin","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}