mastra-ai/mastra · error · Error
Thread knowledge scope requires resource and org ancestors
Error message
Thread knowledge scope requires resource and org ancestors
What it means
Scopes are strictly hierarchical: a thread-scoped entry ('thread:<id>') is only meaningful beneath its resource and org ancestors. canonicalizeKnowledgeScope therefore requires that any scope containing a thread entry also contains the corresponding resource and org entries.
Source
Thrown at packages/core/src/storage/domains/knowledge/base.ts:295
const entriesByLevel = new Map<KnowledgeScopeLevel, string>();
for (const entry of scope) {
const separator = entry.indexOf(':');
const level = entry.slice(0, separator) as KnowledgeScopeLevel;
const id = entry.slice(separator + 1);
if (separator <= 0 || !id || id.includes('\u001f') || SCOPE_ORDER[level] === undefined) {
throw new Error(`Invalid knowledge scope entry: ${entry}`);
}
const existing = entriesByLevel.get(level);
if (existing && existing !== entry) {
throw new Error(`Knowledge scope contains multiple ${level} entries`);
}
entriesByLevel.set(level, entry);
}
if (entriesByLevel.size === 0) {
throw new Error('Knowledge scope cannot be empty');
}
if (entriesByLevel.has('thread') && (!entriesByLevel.has('resource') || !entriesByLevel.has('org'))) {
throw new Error('Thread knowledge scope requires resource and org ancestors');
}
if (entriesByLevel.has('resource') && !entriesByLevel.has('org')) {
throw new Error('Resource knowledge scope requires an org ancestor');
}
const unique = [...new Set(scope)];
unique.sort((a, b) => {
const aLevel = a.slice(0, a.indexOf(':')) as KnowledgeScopeLevel;
const bLevel = b.slice(0, b.indexOf(':')) as KnowledgeScopeLevel;
const aOrder = SCOPE_ORDER[aLevel] ?? Number.MAX_SAFE_INTEGER;
const bOrder = SCOPE_ORDER[bLevel] ?? Number.MAX_SAFE_INTEGER;
return aOrder - bOrder || a.localeCompare(b);
});
return unique;
}
export function knowledgeScopeKey(scope: KnowledgeScope): string {
return canonicalizeKnowledgeScope(scope).join('\u001f');View on GitHub (pinned to 75dd419e61)
Solutions
- Always pass the full ancestor chain: ['org:<o>', 'resource:<r>', 'thread:<t>'].
- Use expandKnowledgeScope(context, 'thread') to derive a properly ancestor-complete thread scope instead of hand-building it.
- When narrowing, keep all wider-level entries and only swap the narrowest one.
- Validate presence of every ancestor level in a helper before calling knowledge APIs.
Example fix
// before
const scope = [`thread:${threadId}`];
// after
const scope = [`org:${orgId}`, `resource:${resourceId}`, `thread:${threadId}`]; Defensive patterns
Strategy: validation
Validate before calling
function hasThreadAncestors(scope: string[]): boolean {
const levels = new Set(scope.map(e => e.slice(0, e.indexOf(':'))));
if (levels.has('thread')) return levels.has('resource') && levels.has('org');
if (levels.has('resource')) return levels.has('org');
return levels.size > 0;
} Prevention
- Always carry the full ancestor chain org -> resource -> thread in scope objects.
- Derive thread scopes with expandKnowledgeScope(context, 'thread') instead of manual assembly.
- When narrowing, replace only the narrowest level; keep ancestors.
When it happens
Trigger: Calling any knowledge API with scope ['org:a', 'thread:t1'] (missing resource) or ['thread:t1'] alone; dropping the resource entry when narrowing a scope from resource to thread level.
Common situations: Constructing thread scope from just a threadId; copying a scope array and deleting the resource line for 'narrowing'; passing expandKnowledgeScope output of the wrong level back in as raw context.
Related errors
- Resource knowledge scope requires an org ancestor
- Cannot expand knowledge scope to ${level}: context has no ${
- Invalid knowledge scope entry: ${entry}
- Knowledge scope contains multiple ${level} entries
- Knowledge scope cannot be empty
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/cb66d08349c9a300.
Report an issue: GitHub.