mastra-ai/mastra · error · Error

Resource knowledge scope requires an org ancestor

Error message

Resource knowledge scope requires an org ancestor

What it means

A resource-scoped entry ('resource:<id>') requires its org ancestor ('org:<id>') in the same scope, since resources live under orgs. canonicalizeKnowledgeScope enforces this and throws when a resource entry appears without an org entry.

Source

Thrown at packages/core/src/storage/domains/knowledge/base.ts:298

    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');
}

export function isKnowledgeScopeVisible(recordScope: KnowledgeScope, queryScope: KnowledgeScope): boolean {

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Include the org entry whenever a resource entry is present: ['org:<o>', 'resource:<r>'].
  2. Store/resolve the owning orgId alongside resourceIds in your domain layer so scopes can always be composed completely.
  3. Derive scopes via expandKnowledgeScope from a full context scope rather than assembling levels piecemeal.

Example fix

// before
const scope = [`resource:${resourceId}`];
// after
const scope = [`org:${orgId}`, `resource:${resourceId}`];
Defensive patterns

Strategy: validation

Validate before calling

function requireOrgWithResource(scope: string[]): void {
  const levels = new Set(scope.map(e => e.slice(0, e.indexOf(':'))));
  if (levels.has('resource') && !levels.has('org')) {
    throw new Error('Resource scope entry requires an org:<id> ancestor in the same scope');
  }
}

Prevention

When it happens

Trigger: Passing scope ['resource:r1'] or ['resource:r1', 'thread:t1'] without an org entry to any knowledge API that canonicalizes scope.

Common situations: Assuming the library can look up the org for a resource automatically (it cannot; scope must be self-contained); dropping the org entry during scope trimming; building scopes in services that only know the resource id.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/b1591002e70e27c2. Report an issue: GitHub.