mastra-ai/mastra · error
Pin limit reached: the set holds at most ${options.maxPins}.
Error message
Pin limit reached: the set holds at most ${options.maxPins}. Unpin something first. What it means
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.
Source
Thrown at packages/memory/src/processors/observational-memory/subconscious/pinned.ts:115
pins.push(...page.records);
after = page.nextCursor;
} while (after);
return { nodeId, pins };
}
function totalCharacters(pins: KnowledgeRecord[]): number {
return pins.reduce((sum, pin) => sum + pin.text.length, 0);
}
function assertBudget(
options: PinnedToolsOptions,
pins: KnowledgeRecord[],
incomingText: string,
replacing?: KnowledgeRecord,
): void {
const kept = replacing ? pins.filter(pin => pin.id !== replacing.id) : pins;
if (!replacing && kept.length >= options.maxPins) {
throw new Error(`Pin limit reached: the set holds at most ${options.maxPins}. Unpin something first.`);
}
if (totalCharacters(kept) + incomingText.length > options.maxCharacters) {
throw new Error(`Pin budget exceeded: the pin set is limited to ${options.maxCharacters} characters in total.`);
}
}
// Pins cannot be written broader than the resource level: the reserved node
// is anchored at (or below) the resource, and an org-scoped pin would only be
// resolvable from the resource that created it, which is a silent-loss trap.
function clampPinLevel(level: KnowledgeScopeLevel): KnowledgeScopeLevel {
return level === 'org' ? 'resource' : level;
}
function resolveWriteScope(options: PinnedToolsOptions, level?: KnowledgeScopeLevel): KnowledgeScope {
// An unscoped pin under a thread ceiling narrows to the ceiling instead of
// failing the assert on every call: pins are model-driven, so a config that
// makes the default request throw would be a tool error every turn.
let effective = clampPinLevel(level ?? options.defaultScope);View on GitHub (pinned to 75dd419e61)
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
Example fix
// before: appending when already at cap
await pinTool.execute({ text: 'new fact' });
// Error: Pin limit reached: the set holds at most 10. Unpin something first.
// after: replace the least useful pin
await pinTool.execute({ text: 'new fact', replaceId: oldestPin.id }); Defensive patterns
Strategy: validation
Validate before calling
const pins = await listPins(memory);
if (pins.length >= maxPins) {
throw new Error('Pin set is at capacity; unpin or replace before pinning new content.');
} Type guard
function canAddPin(pins, maxPins) {
return Array.isArray(pins) && pins.length < maxPins;
} Try / catch
try {
await pinTool.execute({ text });
} catch (err) {
if (err.message.startsWith('Pin limit reached')) {
// unpin the least valuable pin or replace it, then retry
} else throw err;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: Long-running resources accumulating pins until the cap; maxPins lowered in config after pins already exist; automated flows pinning without ever unpinning.
Related errors
- Pin budget exceeded: the pin set is limited to ${options.max
- Knowledge node is not a skill: ${normalizedName}
- Pin not found: ${recordId}
- Record is not a pin: ${recordId}
- AGENT_NETWORK_OBSERVATIONAL_MEMORY_UNSUPPORTED
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/15d7b1b7fd72e642.
Report an issue: GitHub.