{"record":{"id":"69d77bd6a839d39a","repo":"mastra-ai/mastra","slug":"extractor-name-name-must-produce-a-non-empty","errorCode":null,"errorMessage":"Extractor name \"${name}\" must produce a non-empty slug.","messagePattern":"Extractor name \"(.+?)\" must produce a non-empty slug\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/memory/src/processors/observational-memory/extractor.ts","lineNumber":109,"sourceCode":"      normalized += char;\n      previousWasSeparator = false;\n      continue;\n    }\n    if (char === \"'\" || char === '\"' || char === '`') {\n      continue;\n    }\n    if (!previousWasSeparator && normalized.length > 0) {\n      normalized += '-';\n      previousWasSeparator = true;\n    }\n  }\n\n  return normalized.endsWith('-') ? normalized.slice(0, -1) : normalized;\n}\n\nfunction assertValidSlug(slug: string, name: string): void {\n  if (!slug) {\n    throw new Error(`Extractor name \"${name}\" must produce a non-empty slug.`);\n  }\n  const first = slug.charCodeAt(0);\n  const last = slug.charCodeAt(slug.length - 1);\n  const startsWithLetter = first >= 97 && first <= 122;\n  const endsWithLetterOrNumber = (last >= 97 && last <= 122) || (last >= 48 && last <= 57);\n  const hasOnlySlugCharacters = [...slug].every(char => {\n    const code = char.charCodeAt(0);\n    return (code >= 97 && code <= 122) || (code >= 48 && code <= 57) || char === '-';\n  });\n  if (!startsWithLetter || !endsWithLetterOrNumber || !hasOnlySlugCharacters) {\n    throw new Error(`Extractor name \"${name}\" produced invalid slug \"${slug}\".`);\n  }\n}\n\nexport class Extractor<T = unknown> {\n  readonly name: string;\n  readonly slug: string;\n  readonly instructions: string;","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/memory/src/processors/observational-memory/extractor.ts#L91-L127","documentation":"Extractor names are slugified into identifiers used in paths/metadata. If the slugification of an extractor's name yields an empty string — typically because the name contains no slug-able characters — assertValidSlug throws this error.","triggerScenarios":"Constructing an Extractor (or registering one in validateExtractorList) with a name consisting solely of characters stripped by slugification (e.g. \"!!!\", \"   \", \"---\" or non-ASCII-only names that normalize to nothing).","commonSituations":"Auto-generating extractor names from user labels/emojis; i18n names in scripts that slugify to empty; building extractors programmatically from config where name defaults to punctuation.","solutions":["Give the extractor an ASCII alphanumeric name (e.g. 'user-preferences')","If the source name is derived from user input, provide an explicit fallback slug-able name when slugification would empty it","Trim/replace non-alphanumeric characters before constructing the Extractor"],"exampleFix":"// before\nnew Extractor({ name: '!!!', instructions: '...' });\n\n// after\nnew Extractor({ name: 'key-facts', instructions: '...' });","handlingStrategy":"validation","validationCode":"const slugify = (n: string) => n.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');\nif (!slugify(name)) throw new Error(`Extractor name \"${name}\" must contain slug-able characters`);","typeGuard":null,"tryCatchPattern":"try {\n  new Extractor({ name: userLabel, instructions });\n} catch (err) {\n  if (err instanceof Error && err.message.includes('non-empty slug')) {\n    return new Extractor({ name: 'extractor-' + Date.now().toString(36), instructions });\n  }\n  throw err;\n}","preventionTips":["Require ASCII alphanumeric extractor names at config-creation time","Provide deterministic fallback names for user-derived extractor labels","Add a smoke test that slugifies every configured extractor name"],"tags":["observational-memory","extractor","naming","input-validation"],"backgroundTag":"invalid-identifier-name","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}