{"record":{"id":"5482dfa5a6f58241","repo":"mastra-ai/mastra","slug":"extractor-extractor-slug-output-did-not-match","errorCode":null,"errorMessage":"Extractor \"${extractor.slug}\" output did not match its schema: ${failures[0] ?? 'invalid value'}","messagePattern":"Extractor \"(.+?)\" output did not match its schema: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/memory/src/processors/observational-memory/extractor.ts","lineNumber":276,"sourceCode":"      add(JSON.parse(trimmed));\n    } catch {\n      // Plain strings are valid extractor values.\n    }\n  }\n\n  return candidates;\n}\n\nexport function parseExtractorValue<T>(extractor: Extractor<T>, raw: string): T {\n  const failures: string[] = [];\n  for (const candidate of candidateValues(raw)) {\n    const parsed = extractor.schema.safeParse(candidate);\n    if (parsed.success) {\n      return parsed.data;\n    }\n    failures.push(parsed.error.message);\n  }\n  throw new Error(`Extractor \"${extractor.slug}\" output did not match its schema: ${failures[0] ?? 'invalid value'}`);\n}\n\nexport interface ParsedExtractedValues {\n  values: Record<string, unknown>;\n  failures: Array<{ slug: string; error: string }>;\n}\n\nfunction parseExtractedValuesObject(raw: string): Record<string, unknown> | undefined {\n  const trimmed = raw.trim();\n  if (!trimmed || trimmed.startsWith('Write only the extracted values JSON object here.')) {\n    return undefined;\n  }\n\n  const parsed = JSON.parse(trimmed) as unknown;\n  if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n    throw new Error(`${EXTRACTED_VALUES_TAG} must contain a JSON object.`);\n  }\n  return parsed as Record<string, unknown>;","sourceCodeStart":258,"sourceCodeEnd":294,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/memory/src/processors/observational-memory/extractor.ts#L258-L294","documentation":"`parseExtractorValue` validates the raw text extracted from an output tag against the extractor's Zod schema, trying JSON.parse first and then the plain string as candidates. If no candidate passes `schema.safeParse`, the library throws with the first Zod failure message. The result is captured in parseExtractedValues as a per-slug failure, but this underlying throw surfaces when the model output doesn't conform to the declared schema.","triggerScenarios":"Structured extractor's schema expects a number/object but the model emitted prose; JSON in the tag is valid JSON but wrong shape (missing fields, string instead of number); the model wrapped the value in markdown fences or extra text inside the tag; inline `<slug>` tag content that is a plain string but schema requires an object.","commonSituations":"Small/weak models ignoring JSON formatting instructions; schema too strict (e.g. .url(), enum, min length) for what the model produces; changing a schema after deployment while persisted/old outputs use the old shape; nested quotes breaking JSON.parse.","solutions":["Loosen or correct the Zod schema so valid model outputs parse (add coercion, .catch(), optional fields, .default()).","Sharpen the extractor `instructions` to specify the exact output format (e.g. 'Return only a JSON object with fields X and Y').","Use a more capable model for the observer/reflector if it repeatedly fails to produce valid JSON.","Handle the failure gracefully via parseExtractedValues' returned `failures` array rather than letting the throw propagate, and retry the extraction."],"exampleFix":"// before\nschema: z.object({ count: z.number() }) // model returns \"{\\\"count\\\": \\\"3\\\"}\"\n// after\nschema: z.object({ count: z.coerce.number() })","handlingStrategy":"fallback","validationCode":"const preview = extractRawTag(output, slug);\nconst result = schema.safeParse(preview);\nif (!result.success) logger.warn('Extractor output will fail schema', { slug, issues: result.error.issues });","typeGuard":"function matchesSchema(value, schema) { return schema.safeParse(value).success; }","tryCatchPattern":"const { values, failures } = parseExtractedValues(output, extractors);\nfor (const f of failures) {\n  if (f.error.includes('did not match its schema')) {\n    logger.warn('Schema mismatch, will retry extraction', { slug: f.slug });\n  }\n}","preventionTips":["Prefer lenient schemas (z.coerce, .catch(), .default()) so common model quirks still parse.","State the exact JSON shape in extractor instructions, including types and example output.","Monitor the failures array returned by parseExtractedValues to detect chronic schema mismatches per model.","Pin extraction to a model known to follow structured-output instructions."],"tags":["schema-validation","zod","llm-output","observational-memory"],"backgroundTag":"schema-validation-failed","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}