{"record":{"id":"f8982ce44183d23e","repo":"remix-run/react-router","slug":"a-meta-object-uses-an-invalid-tagname-tagname","errorCode":null,"errorMessage":"A meta object uses an invalid tagName: ${tagName}. Expected either 'link' or 'meta'","messagePattern":"A meta object uses an invalid tagName: (.+?)\\. Expected either 'link' or 'meta'","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/react-router/lib/dom/ssr/components.tsx","lineNumber":687,"sourceCode":"    }\n\n    match.meta = routeMeta;\n    matches[i] = match;\n    meta = [...routeMeta];\n    leafMeta = meta;\n  }\n\n  return (\n    <>\n      {meta.flat().map((metaProps) => {\n        if (!metaProps) {\n          return null;\n        }\n\n        if (\"tagName\" in metaProps) {\n          let { tagName, ...rest } = metaProps;\n          if (!isValidMetaTag(tagName)) {\n            console.warn(\n              `A meta object uses an invalid tagName: ${tagName}. Expected either 'link' or 'meta'`,\n            );\n            return null;\n          }\n          let Comp = tagName;\n          return <Comp key={JSON.stringify(rest)} {...rest} />;\n        }\n\n        if (\"title\" in metaProps) {\n          return <title key=\"title\">{String(metaProps.title)}</title>;\n        }\n\n        if (\"charset\" in metaProps) {\n          metaProps.charSet ??= metaProps.charset;\n          delete metaProps.charset;\n        }\n\n        if (\"charSet\" in metaProps && metaProps.charSet != null) {","sourceCodeStart":669,"sourceCodeEnd":705,"githubUrl":"https://github.com/remix-run/react-router/blob/6beaca39526d5716c3c112ebb0782765baa5a9ce/packages/react-router/lib/dom/ssr/components.tsx#L669-L705","documentation":"When the <Meta> component renders a route's `meta` export, entries carrying a `tagName` key are validated by isValidMetaTag, which only accepts \"meta\" or \"link\". Any other tag (e.g., \"script\", \"base\", or a typo like \"Meta\") logs this warning and that entry renders null — the page still renders, just without that head tag. Titles, charSet, and property/name-based entries have their own dedicated shapes and don't use tagName.","triggerScenarios":"A route module's `meta` function (or array) returns an object like `{ tagName: \"script\", type: \"application/ld+json\", ... }` or any tagName other than exactly \"meta\"/\"link\" — note the check is case-sensitive.","commonSituations":"Trying to inject JSON-LD/structured data or analytics scripts through the meta export; casing typos (\"Meta\", \"Link\"); assuming meta supports arbitrary head tags because it returns objects.","solutions":["Use only `tagName: \"meta\"` or `tagName: \"link\"` for those entries","For titles use `{ title: \"...\" }`; for scripts (JSON-LD, analytics) render a <script> in the route component or root layout instead of the meta export","Check casing — \"Meta\"/\"Link\" are invalid; only lowercase passes"],"exampleFix":"// before - app/routes/product.tsx\nexport const meta = () => [\n  { tagName: \"script\", type: \"application/ld+json\", children: JSON.stringify(ld) },\n];\n\n// after\nexport const meta = () => [{ title: \"Product\" }];\n// in the route component / root layout:\n<script type=\"application/ld+json\" dangerouslySetInnerHTML={{ __html: JSON.stringify(ld) }} />","handlingStrategy":"type-guard","validationCode":"// filter meta entries before returning them from a route's `meta` export\nfunction safeMeta(entries) {\n  return entries.filter((e) => !e?.tagName || e.tagName === \"meta\" || e.tagName === \"link\");\n}\nexport const meta = () => safeMeta([{ tagName: \"script\", rel: \"x\" }, { title: \"OK\" }]);","typeGuard":"type MetaTagName = \"meta\" | \"link\";\nfunction isValidMetaTag(tagName: unknown): tagName is MetaTagName {\n  return tagName === \"meta\" || tagName === \"link\";\n}\n// usage: if (\"tagName\" in entry && !isValidMetaTag(entry.tagName)) drop(entry);","tryCatchPattern":null,"preventionTips":["Type meta exports against MetaDescriptor (`satisfies MetaDescriptor[]`) so invalid tagName values fail at compile time","Remember the meta export only supports meta/link/title/charset shapes — render <script> tags in components instead","tagName is case-sensitive: always lowercase \"meta\"/\"link\""],"tags":["meta","seo","head-tags","ssr","route-module"],"backgroundTag":"invalid-meta-tag","analyzedSha":"6beaca39526d5716c3c112ebb0782765baa5a9ce","analyzedAt":"2026-08-18T18:04:14.938Z","schemaVersion":2},"datasetVersion":"2026-09-01T03:17:15.561Z"}