mastra-ai/mastra · error · Error
Extractor slug "${extractor.slug}" is reserved by Observatio
Error message
Extractor slug "${extractor.slug}" is reserved by Observational Memory. What it means
`validateExtractorList` runs when extractor lists are composed for a processor and re-checks each extractor's slug against the reserved XML tag set (observations, observation, extracted-values, thread, message, messages, conversation, history, system, user, assistant, tool, and built-in slugs current-task/suggested-response/thread-title). Non-internal extractors with a reserved slug are rejected because their output tags would collide with Observational Memory's own parsing protocol. This is a defense-in-depth check at composition time, in addition to the constructor guard.
Source
Thrown at packages/memory/src/processors/observational-memory/extractor.ts:222
},
this.internal,
);
}
}
export async function resolveExtractors(
extractors: readonly Extractor<any>[],
context: ExtractorRuntimeContext,
): Promise<Extractor<any>[]> {
return Promise.all(extractors.map(extractor => extractor.resolve(context)));
}
export function validateExtractorList(extractors: readonly Extractor<any>[]): Extractor<any>[] {
const seen = new Map<string, string>();
for (const extractor of extractors) {
assertValidSlug(extractor.slug, extractor.name);
if (!extractor.internal && RESERVED_XML_TAGS.has(extractor.slug)) {
throw new Error(`Extractor slug "${extractor.slug}" is reserved by Observational Memory.`);
}
const previous = seen.get(extractor.slug);
if (previous) {
throw new Error(`Duplicate extractor slug "${extractor.slug}" from "${previous}" and "${extractor.name}".`);
}
seen.set(extractor.slug, extractor.name);
}
return [...extractors];
}
function isJsonLike(value: string): boolean {
return /^(?:[\[{"-]|\d|true\b|false\b|null\b)/.test(value.trim());
}
function candidateValues(raw: string): unknown[] {
const trimmed = raw.trim();
const candidates: unknown[] = [];
const add = (value: unknown) => {View on GitHub (pinned to 75dd419e61)
Solutions
- Rename the extractor so its slug differs from all reserved tags.
- If listing extractors from user input, filter/validate slugs against RESERVED_XML_TAGS before composing the list.
- Reuse isBuiltInExtractorSlug / slugifyExtractorName to pre-check names.
Example fix
// before
new Extractor({ name: 'Messages', instructions: 'List key messages' });
// after
new Extractor({ name: 'Key Messages', instructions: 'List key messages' }); Defensive patterns
Strategy: validation
Validate before calling
import { slugifyExtractorName, isBuiltInExtractorSlug } from '@mastra/memory/processors/observational-memory';
for (const e of extractors) {
if (!e.internal && RESERVED_XML_TAGS.has(e.slug)) throw new Error(`Reserved slug: ${e.slug}`);
} Type guard
function allSlugsSafe(list) {
return list.every(e => e.internal || !RESERVED.has(e.slug));
} Try / catch
try {
validateExtractorList(extractors);
} catch (e) {
if (e.message.includes('is reserved by Observational Memory')) {
logger.error('Extractor list contains reserved slug', { msg: e.message });
} else { throw e; }
} Prevention
- Run validateExtractorList in your own config-loading layer before handing extractors to the processor.
- Sanitize user-supplied extractor names against the reserved tag list at ingestion time.
- Add a unit test asserting your production extractor list validates cleanly.
When it happens
Trigger: Composing a list containing an extractor constructed with `internal = true` bypass semantics won't help here — any user-supplied extractor whose slugified name matches a reserved tag (e.g. 'User', 'History', 'Thread Title'); manually constructed Extractor instances passed via ObservationalMemory config; extractors produced by a helper/factory that assembles names dynamically and happens to hit a reserved word.
Common situations: Dynamically generated extractor names from user config; trying to shadow built-in extractors; a name like 'Messages!' that slugifies to 'messages'.
Related errors
- Extractor slug "${slug}" is reserved by Observational Memory
- Extractor name "${name}" must produce a non-empty slug.
- Extractor name "${name}" produced invalid slug "${slug}".
- Extractor name is required.
- Duplicate extractor slug "${extractor.slug}" from "${previou
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/9a7bf85cc2f18545.
Report an issue: GitHub.