{"record":{"id":"15d7b1b7fd72e642","repo":"mastra-ai/mastra","slug":"pin-limit-reached-the-set-holds-at-most-options","errorCode":null,"errorMessage":"Pin limit reached: the set holds at most ${options.maxPins}. Unpin something first.","messagePattern":"Pin limit reached: the set holds at most (.+?)\\. Unpin something first\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/memory/src/processors/observational-memory/subconscious/pinned.ts","lineNumber":115,"sourceCode":"    pins.push(...page.records);\n    after = page.nextCursor;\n  } while (after);\n  return { nodeId, pins };\n}\n\nfunction totalCharacters(pins: KnowledgeRecord[]): number {\n  return pins.reduce((sum, pin) => sum + pin.text.length, 0);\n}\n\nfunction assertBudget(\n  options: PinnedToolsOptions,\n  pins: KnowledgeRecord[],\n  incomingText: string,\n  replacing?: KnowledgeRecord,\n): void {\n  const kept = replacing ? pins.filter(pin => pin.id !== replacing.id) : pins;\n  if (!replacing && kept.length >= options.maxPins) {\n    throw new Error(`Pin limit reached: the set holds at most ${options.maxPins}. Unpin something first.`);\n  }\n  if (totalCharacters(kept) + incomingText.length > options.maxCharacters) {\n    throw new Error(`Pin budget exceeded: the pin set is limited to ${options.maxCharacters} characters in total.`);\n  }\n}\n\n// Pins cannot be written broader than the resource level: the reserved node\n// is anchored at (or below) the resource, and an org-scoped pin would only be\n// resolvable from the resource that created it, which is a silent-loss trap.\nfunction clampPinLevel(level: KnowledgeScopeLevel): KnowledgeScopeLevel {\n  return level === 'org' ? 'resource' : level;\n}\n\nfunction resolveWriteScope(options: PinnedToolsOptions, level?: KnowledgeScopeLevel): KnowledgeScope {\n  // An unscoped pin under a thread ceiling narrows to the ceiling instead of\n  // failing the assert on every call: pins are model-driven, so a config that\n  // makes the default request throw would be a tool error every turn.\n  let effective = clampPinLevel(level ?? options.defaultScope);","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/memory/src/processors/observational-memory/subconscious/pinned.ts#L97-L133","documentation":"Pin writes enforce a budget via assertBudget before appending to the reserved pinned-knowledge node. The set may hold at most options.maxPins pins; when adding a NEW pin (no replacing record) would meet or exceed that count, the tool throws. This keeps the always-injected pin set small and predictable. Replacing an existing pin bypasses the count check because the set size does not grow.","triggerScenarios":"Calling the pin tool when the current pin count (excluding any replaced pin) is already >= maxPins and the write is an append, not a replacement.","commonSituations":"Long-running resources accumulating pins until the cap; maxPins lowered in config after pins already exist; automated flows pinning without ever unpinning.","solutions":["Unpin an existing record first, then pin the new one","Replace an existing pin instead of adding (pass the record being replaced so it is filtered out of the count)","Raise options.maxPins in the pinned tools configuration","Audit the pin set (list pins) and prune stale entries"],"exampleFix":"// before: appending when already at cap\nawait pinTool.execute({ text: 'new fact' });\n// Error: Pin limit reached: the set holds at most 10. Unpin something first.\n// after: replace the least useful pin\nawait pinTool.execute({ text: 'new fact', replaceId: oldestPin.id });","handlingStrategy":"validation","validationCode":"const pins = await listPins(memory);\nif (pins.length >= maxPins) {\n  throw new Error('Pin set is at capacity; unpin or replace before pinning new content.');\n}","typeGuard":"function canAddPin(pins, maxPins) {\n  return Array.isArray(pins) && pins.length < maxPins;\n}","tryCatchPattern":"try {\n  await pinTool.execute({ text });\n} catch (err) {\n  if (err.message.startsWith('Pin limit reached')) {\n    // unpin the least valuable pin or replace it, then retry\n  } else throw err;\n}","preventionTips":["List pins before appending and prefer replace over add","Pair every pin workflow with an unpin/prune step","Tune maxPins to the workload and monitor pin count","Watch for config changes that lower maxPins below the current set size"],"tags":["quota","knowledge-store","observational-memory"],"backgroundTag":"pin-limit-exceeded","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}