{"record":{"id":"f13a8208782538f2","repo":"withastro/astro","slug":"mdx-a-s-tteri-plugin-attempted-to-inject-invalid","errorCode":null,"errorMessage":"[MDX] A Sätteri plugin attempted to inject invalid frontmatter. Ensure `ctx.data.astro.frontmatter` is a valid object that is not `null` or `undefined`.","messagePattern":"\\[MDX\\] A Sätteri plugin attempted to inject invalid frontmatter\\. Ensure `ctx\\.data\\.astro\\.frontmatter` is a valid object that is not `null` or `undefined`\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/integrations/mdx/src/satteri/index.ts","lineNumber":151,"sourceCode":"\t\t\t\t\t\t? {}\n\t\t\t\t\t\t: { smartPunctuation: mdxOptions.smartypants !== false }),\n\t\t\t\t},\n\t\t\t\tfileURL: pathToFileURL(filePath),\n\t\t\t\tjsxImportSource: 'astro',\n\t\t\t\telementAttributeNameCase: 'html',\n\t\t\t\tdata: { astro: astroData },\n\t\t\t});\n\t\t\tlet compiled = mdxResult.code;\n\n\t\t\t// Read the returned bag, not the seeded reference, so a plugin that replaces it is honored.\n\t\t\tconst astro = mdxResult.data.astro;\n\t\t\tconst headings = astro?.headings ?? [];\n\t\t\tconst astroMetadata = mdxResult.data.__astroMetadata ?? createDefaultAstroMetadata();\n\n\t\t\t// Plugins may have mutated frontmatter; emit the final value.\n\t\t\tconst resolvedFrontmatter = astro?.frontmatter;\n\t\t\tif (!resolvedFrontmatter || !isFrontmatterValid(resolvedFrontmatter)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t'[MDX] A Sätteri plugin attempted to inject invalid frontmatter. Ensure `ctx.data.astro.frontmatter` is a valid object that is not `null` or `undefined`.',\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tcompiled = compiled.replace(/^export default MDXContent;\\s*$/m, '');\n\n\t\t\tif (imageImportInfo.hasImages) {\n\t\t\t\t// `vite-plugin-mdx-postprocess` wraps Content to map\n\t\t\t\t// `astro-image` → `components.img ?? __AstroImage__`, so a user's\n\t\t\t\t// `export const components = { img: ... }` override is honored.\n\t\t\t\tcompiled += `\\nimport { Image as ${ASTRO_IMAGE_IMPORT} } from \"astro:assets\";`;\n\t\t\t\tfor (const [src, importName] of imageImportInfo.importedImages) {\n\t\t\t\t\tcompiled += `\\nimport ${importName} from ${JSON.stringify(src)};`;\n\t\t\t\t}\n\t\t\t\tcompiled += `\\nexport const ${USES_ASTRO_IMAGE_FLAG} = true;`;\n\t\t\t}\n\n\t\t\tcompiled += `\\nexport const frontmatter = ${JSON.stringify(resolvedFrontmatter)};`;","sourceCodeStart":133,"sourceCodeEnd":169,"githubUrl":"https://github.com/withastro/astro/blob/d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca/packages/integrations/mdx/src/satteri/index.ts#L133-L169","documentation":"After compiling MDX through the Sätteri pipeline, the integration reads `mdxResult.data.astro.frontmatter` (the final, post-plugin value) and re-validates it. If the resolved frontmatter is missing or not a valid JSON object, it throws a plain `Error` attributing the failure to a Sätteri plugin. This catches plugins that replaced or nulled the frontmatter bag during compilation.","triggerScenarios":"A remark/rehype/Sätteri plugin assigns `ctx.data.astro.frontmatter` to null/undefined or a non-serializable value during compile. A plugin that swaps out the whole `data.astro` object without preserving `frontmatter`. Async frontmatter mutation that resolves after the read.","commonSituations":"Custom Sätteri/remark plugin overriding frontmatter. Plugin compatibility issue across MDX versions. Frontmatter intentionally cleared in a transform.","solutions":["Make any plugin that touches frontmatter always leave `ctx.data.astro.frontmatter` as a plain JSON object.","If you replace `data.astro`, copy `frontmatter` over: `{ ...newAstro, frontmatter: existing.frontmatter ?? {} }`.","Verify plugin order so a later plugin doesn't null frontmatter after earlier setup.","Default frontmatter to `{}` rather than allowing it to become undefined."],"exampleFix":"// before\nfile.data.astro = { ...newData }; // drops frontmatter\n\n// after\nfile.data.astro = { ...newData, frontmatter: file.data.astro?.frontmatter ?? {} };","handlingStrategy":"validation","validationCode":"function isValidFrontmatter(fm: unknown): boolean {\n  return fm !== null && fm !== undefined && typeof fm === 'object' && !Array.isArray(fm);\n}","typeGuard":"function isPlainFrontmatter(v: unknown): v is Record<string, unknown> {\n  return v !== null && typeof v === 'object' && !Array.isArray(v);\n}","tryCatchPattern":null,"preventionTips":["Preserve `frontmatter` when replacing `data.astro`.","Default frontmatter to `{}` in any plugin that may clear it.","Pin plugin order so frontmatter is finalized before re-validation."],"tags":["mdx","satteri","frontmatter","plugins","build"],"backgroundTag":null,"analyzedSha":"d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca","analyzedAt":"2026-08-12T13:37:29.035Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}