{"record":{"id":"4cef1eda812fabab","repo":"mastra-ai/mastra","slug":"extracted-values-tag-must-contain-a-json-object","errorCode":null,"errorMessage":"${EXTRACTED_VALUES_TAG} must contain a JSON object.","messagePattern":"(.+?) must contain a JSON object\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/memory/src/processors/observational-memory/extractor.ts","lineNumber":292,"sourceCode":"    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>;\n}\n\nexport function parseExtractedValues(output: string, extractors: readonly Extractor<any>[]): ParsedExtractedValues {\n  const values: Record<string, unknown> = {};\n  const failures: Array<{ slug: string; error: string }> = [];\n  const inlineExtractors = extractors.filter(extractor => extractor.mode === 'inline');\n\n  const regex = new RegExp(`<${EXTRACTED_VALUES_TAG}>([\\\\s\\\\S]*?)<\\\\/${EXTRACTED_VALUES_TAG}>`, 'gi');\n  const matches = [...output.matchAll(regex)];\n  for (const match of matches) {\n    try {\n      const extractedValues = parseExtractedValuesObject(match[1] ?? '');\n      if (!extractedValues) {\n        continue;\n      }\n","sourceCodeStart":274,"sourceCodeEnd":310,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/memory/src/processors/observational-memory/extractor.ts#L274-L310","documentation":"When the observer/reflector output contains an `<extracted-values>` block, Observational Memory parses its contents as a JSON object keyed by extractor slug. `parseExtractedValuesObject` throws this error when the tag's content is valid JSON but not an object — e.g. an array, string, number, or `null`. The error is recorded as a failure under the 'extracted-values' slug rather than crashing the stream.","triggerScenarios":"Model emits a JSON array `[...]` inside <extracted-values> instead of an object; model emits a bare string or number; model wraps a JSON array of {slug,value} pairs; JSON.stringify of an array being echoed back by the model.","commonSituations":"Models that interpret 'extracted values' as a list rather than a map; prompts with multiple extractors leading the model to output an array of records; weak models ignoring the object-shape instruction.","solutions":["Strengthen extractor instructions to say 'Output a single JSON object whose keys are the extractor tags and whose values are the extracted values.'","Post-process the model output before parsing (or rely on the recorded failure and retry the extraction pass).","Use a stronger model for the reflector/observer if arrays persist.","Catch failures via the ParsedExtractedValues.failures array and inject corrective feedback on retry."],"exampleFix":"// model output before\n<extracted-values>[{\"user-goals\":\"run a marathon\"}]</extracted-values>\n// model output after\n<extracted-values>{\"user-goals\":\"run a marathon\"}</extracted-values>","handlingStrategy":"try-catch","validationCode":"function isJsonObjectString(s) {\n  try { const v = JSON.parse(s); return v !== null && typeof v === 'object' && !Array.isArray(v); }\n  catch { return false; }\n}","typeGuard":"function isRecord(v) { return v !== null && typeof v === 'object' && !Array.isArray(v); }","tryCatchPattern":"const { values, failures } = parseExtractedValues(output, extractors);\nconst shapeFailures = failures.filter(f => f.slug === 'extracted-values');\nif (shapeFailures.length) {\n  logger.warn('extracted-values block was not a JSON object; retrying extraction', { error: shapeFailures[0].error });\n}","preventionTips":["Tell the model explicitly: 'inside <extracted-values>, output exactly one JSON object, never an array'.","Include a one-line example object in the extraction prompt.","Treat 'extracted-values' failures from parseExtractedValues as a retry signal with corrective feedback."],"tags":["json","llm-output","parsing","observational-memory"],"backgroundTag":"invalid-json-shape","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}