{"record":{"id":"606c5d14074d8c3e","repo":"withastro/astro","slug":"mdx-a-remark-or-rehype-plugin-attempted-to-injec","errorCode":null,"errorMessage":"[MDX] A remark or rehype plugin attempted to inject invalid frontmatter. Ensure \"astro.frontmatter\" is set to a valid JSON object that is not `null` or `undefined`.","messagePattern":"\\[MDX\\] A remark or rehype plugin attempted to inject invalid frontmatter\\. Ensure \"astro\\.frontmatter\" is set to a valid JSON object that is not `null` or `undefined`\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/integrations/mdx/src/rehype-apply-frontmatter-export.ts","lineNumber":23,"sourceCode":"import type { VFile } from 'vfile';\nimport { jsToTreeNode } from './utils.js';\n\n// Passed metadata to help determine adding charset utf8 by default\ndeclare module 'vfile' {\n\tinterface DataMap {\n\t\tapplyFrontmatterExport?: {\n\t\t\tsrcDir?: URL;\n\t\t};\n\t}\n}\n\nconst exportConstPartialTrueRe = /export\\s+const\\s+partial\\s*=\\s*true/;\n\nexport function rehypeApplyFrontmatterExport() {\n\treturn function (tree: Root, vfile: VFile) {\n\t\tconst frontmatter = vfile.data.astro?.frontmatter;\n\t\tif (!frontmatter || !isFrontmatterValid(frontmatter))\n\t\t\tthrow new Error(\n\t\t\t\t// Copied from Astro core `errors-data`\n\t\t\t\t// TODO: find way to import error data from core\n\t\t\t\t'[MDX] A remark or rehype plugin attempted to inject invalid frontmatter. Ensure \"astro.frontmatter\" is set to a valid JSON object that is not `null` or `undefined`.',\n\t\t\t);\n\t\tconst extraChildren: RootContent[] = [\n\t\t\tjsToTreeNode(`export const frontmatter = ${JSON.stringify(frontmatter)};`),\n\t\t];\n\t\tif (frontmatter.layout) {\n\t\t\textraChildren.unshift(\n\t\t\t\tjsToTreeNode(\n\t\t\t\t\t// NOTE: Use `__astro_*` import names to prevent conflicts with user code\n\t\t\t\t\t/** @see 'vite-plugin-markdown' for layout props reference */\n\t\t\t\t\t`\\\nimport { jsx as __astro_layout_jsx__ } from 'astro/jsx-runtime';\nimport __astro_layout_component__ from ${JSON.stringify(frontmatter.layout)};\n\nexport default function ({ children }) {\n\tconst { layout, ...content } = frontmatter;","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/withastro/astro/blob/d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca/packages/integrations/mdx/src/rehype-apply-frontmatter-export.ts#L5-L41","documentation":"`rehype-apply-frontmatter-export` reads `vfile.data.astro.frontmatter` and, if missing or failing `isFrontmatterValid`, throws a plain `Error`. The plugin then emits `export const frontmatter = {...}` (and a layout import) into the MDX AST. The check guards against remark/rehype plugins that set `astro.frontmatter` to `null`/`undefined` or a non-JSON-serializable value.","triggerScenarios":"A remark/rehype plugin assigns `file.data.astro.frontmatter = null` (or `undefined`, or a circular object). Frontmatter is computed asynchronously and not set by the time this plugin runs. A plugin replaces `file.data.astro` entirely.","commonSituations":"Custom remark plugin that processes frontmatter and forgets to keep a valid object. MDX frontmatter removed conditionally. Plugin ordering issue where a later plugin nulls frontmatter.","solutions":["Ensure any remark/rehype plugin touching frontmatter sets `file.data.astro.frontmatter` to a plain JSON-serializable object (never null/undefined).","Check plugin order in `remarkPlugins`/`rehypePlugins` so frontmatter-setting plugins run before this one and are not later overwritten.","If frontmatter is optional, default it to `{}` instead of null."],"exampleFix":"// before — plugin that breaks frontmatter\nexport function remarkPlugin() {\n  return (tree, file) => {\n    file.data.astro.frontmatter = null;\n  };\n}\n\n// after\nexport function remarkPlugin() {\n  return (tree, file) => {\n    file.data.astro.frontmatter = { ...(file.data.astro.frontmatter ?? {}), ...computed };\n  };\n}","handlingStrategy":"validation","validationCode":"function isFrontmatterValid(fm: unknown): boolean {\n  return fm !== null && fm !== undefined && typeof fm === 'object' && !Array.isArray(fm);\n}\n// in plugin:\nif (!isFrontmatterValid(file.data.astro?.frontmatter)) {\n  file.data.astro = { ...(file.data.astro ?? {}), frontmatter: {} };\n}","typeGuard":"function isValidFrontmatter(fm: unknown): fm is Record<string, unknown> {\n  return fm !== null && typeof fm === 'object' && !Array.isArray(fm);\n}","tryCatchPattern":null,"preventionTips":["Never set `astro.frontmatter` to null/undefined in remark/rehype plugins.","Default frontmatter to `{}` when conditionally cleared.","Verify plugin order so frontmatter is set before MDX export emission."],"tags":["mdx","frontmatter","plugins","build"],"backgroundTag":null,"analyzedSha":"d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca","analyzedAt":"2026-08-12T13:37:29.035Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}