mastra-ai/mastra · error · Error
Skill evidence requires at least two distinct records from t
Error message
Skill evidence requires at least two distinct records from the pending learner worklist.
What it means
The learner's record-skill tool demands evidence: the cited sourceRecordIds must contain at least two distinct IDs, and every ID must belong to the pending learner worklist for the current reflection. This prevents the learner from minting skills (procedural knowledge) from a single observation or from records it was never shown.
Source
Thrown at packages/memory/src/processors/observational-memory/subconscious/learn.ts:92
id: 'knowledge_record_skill',
description:
'Create or update one reusable skill using at least two distinct pending knowledge records. Evidence writes are idempotent across retries.',
inputSchema: {
type: 'object',
properties: {
name: { type: 'string', minLength: 1 },
procedure: { type: 'string', minLength: 1 },
sourceRecordIds: { type: 'array', items: { type: 'string', minLength: 1 }, minItems: 2, uniqueItems: true },
},
required: ['name', 'procedure', 'sourceRecordIds'],
additionalProperties: false,
} satisfies JSONSchema7,
execute: async raw => {
const value = raw as { name: string; procedure: string; sourceRecordIds: string[] };
const sourceIds = [...new Set(value.sourceRecordIds)];
const pending = new Map(input.pendingRecords.map(record => [record.id, record]));
if (sourceIds.length < 2 || sourceIds.some(id => !pending.has(id))) {
throw new Error('Skill evidence requires at least two distinct records from the pending learner worklist.');
}
const normalizedName = value.name.trim();
if (
input.state.recordedName &&
input.state.recordedName.toLocaleLowerCase() !== normalizedName.toLocaleLowerCase()
) {
throw new Error('The learner may record at most one skill per reflection.');
}
input.state.recordedName = normalizedName;
const nodeScope = expandKnowledgeScope(input.scope, input.defaultScope);
let node = await input.store.resolveNode({ name: normalizedName, scope: input.scope });
if (node && node.kind !== 'skill') throw new Error(`Knowledge node is not a skill: ${normalizedName}`);
node ??= await input.store.createNode({ name: normalizedName, kind: 'skill', scope: nodeScope });
const evidence = [];
for (const sourceId of sourceIds) {
const id = evidenceRecordId(sourceId, normalizedName);
const existing = await input.store.getKnowledge({ id });
if (existing) {View on GitHub (pinned to 75dd419e61)
Solutions
- Pick at least two distinct record IDs from the pending worklist handed to the learner in the current reflection
- Dedupe and verify each ID against the pending list before invoking the tool
- Re-run the reflection if the worklist has changed so the learner gets fresh record IDs
Example fix
// before
await tool.execute({ name, procedure, sourceRecordIds: [id] });
// after
const ids = [...new Set(pending.map(r => r.id))].slice(0, 2);
if (ids.length < 2) throw new Error('Need >=2 distinct pending records');
await tool.execute({ name, procedure, sourceRecordIds: ids }); Defensive patterns
Strategy: validation
Validate before calling
const ids = [...new Set(sourceRecordIds)];
const pendingIds = new Set(pendingRecords.map(r => r.id));
if (ids.length < 2 || !ids.every(id => pendingIds.has(id))) {
throw new Error('Need >=2 distinct records from the pending worklist');
} Type guard
function hasEnoughEvidence(ids: string[], pending: { id: string }[]): ids is [string, string, ...string[]] {
const set = new Set(pending.map(p => p.id));
const distinct = ids.filter(id => set.has(id));
return distinct.length >= 2;
} Try / catch
try {
await tool.execute({ name, procedure, sourceRecordIds });
} catch (e) {
if (e instanceof Error && e.message.includes('at least two distinct records')) {
// re-pick evidence from the current pending worklist
} else throw e;
} Prevention
- Dedupe sourceRecordIds before calling
- Only cite records from the current reflection's pending worklist
- Instruct the learner model to gather >=2 observations before recording a skill
When it happens
Trigger: Calling the record-skill tool with fewer than two unique record IDs, duplicate IDs that dedupe to one, or IDs not present in the pendingRecords worklist passed to createLearnerRecordSkillTool (e.g. records from another thread or already-consumed records).
Common situations: LLM citing record IDs it hallucinated or saw in earlier reflections; duplicates in the ID array collapsing below two after dedupe; worklist rotated between planning and tool execution.
Related errors
- MastraClient.deleteThread() requires exactly one of agentId
- Thread ID is required for thread-scoped working memory updat
- Resource ID is required for resource-scoped working memory u
- Thread with id ${threadId} resourceId does not match the cur
- Cannot update working memory: ${scope} ID is required
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/0b3b325f0fd17019.
Report an issue: GitHub.