{"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/52e6c34790cc8ac4e69e6135ace06049867e5c4a/packages/integrations/mdx/src/rehype-apply-frontmatter-export.ts#L5-L41","documentation":"remark/rehype plugins can inject frontmatter into an MDX file by setting `vfile.data.astro.frontmatter`. The MDX integration later re-exports it as `export const frontmatter = ...` and derives layout wiring from it, so the value must be a non-null, non-undefined JSON object. This rehype plugin throws when that data is missing or fails a validity check (e.g. null, a primitive, an array). The message is copied from Astro core's equivalent markdown error.","triggerScenarios":"A custom remark/rehype plugin sets `file.data.astro.frontmatter` to a string/number/boolean/array/null, or deletes/never sets it while another plugin assumes it exists; plugin ordering puts this rehype plugin before the frontmatter-injecting one.","commonSituations":"Writing a frontmatter-injection plugin (e.g. reading title/date from filesystem or CMS) and assigning a non-object; upgrading remark plugins that changed data placement; copy-pasting plugin snippets that mutate vfile.data incorrectly.","solutions":["In your plugin, always assign a plain object: `file.data.astro.frontmatter = { ...file.data.astro.frontmatter, myKey: value }`.","Ensure the injecting plugin runs before rehypeApplyFrontmatterExport (correct remarkPlugins/rehypePlugins order).","Keep values JSON-serializable (no functions, Dates are fine but Class instances are not).","Update @astrojs/mdx and astro — plugin pipeline ordering fixes have landed across versions."],"exampleFix":"// before — plugin injects invalid frontmatter\nfile.data.astro.frontmatter = frontmatterYamlString;\n\n// after — merge a plain object\nfile.data.astro.frontmatter = {\n  ...file.data.astro.frontmatter,\n  ...parseYaml(frontmatterYamlString),\n};","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"type AstroVFileData = { astro?: { frontmatter?: unknown } };\nfunction isValidFrontmatter(v: unknown): v is Record<string, unknown> {\n  return typeof v === 'object' && v !== null && !Array.isArray(v);\n}\n// Inside your remark/rehype plugin, before assignment:\n// const fm = (file.data as AstroVFileData).astro?.frontmatter;\n// if (!isValidFrontmatter(fm)) { /* assign a fresh object instead */ }","tryCatchPattern":null,"preventionTips":["In frontmatter-injecting plugins, merge into a fresh object rather than replacing with arbitrary YAML/JSON parses.","Order the injecting plugin before built-in rehype plugins that consume frontmatter.","Unit-test custom plugins against an MDX fixture so invalid shapes fail in tests, not builds."],"tags":["mdx","frontmatter","remark-plugins","rehype-plugins","build"],"backgroundTag":"invalid-frontmatter","analyzedSha":"52e6c34790cc8ac4e69e6135ace06049867e5c4a","analyzedAt":"2026-08-18T18:48:03.901Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}