{"record":{"id":"d76e427ce00e63ae","repo":"withastro/astro","slug":"shiki-the-language-langstr-doesn-t-exist-fal","errorCode":null,"errorMessage":"[Shiki] The language ${langStr} doesn't exist, falling back to \"plaintext\".","messagePattern":"\\[Shiki\\] The language (.+?) doesn't exist, falling back to \"plaintext\"\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/internal-helpers/src/shiki.ts","lineNumber":198,"sourceCode":"\t\tengine: shikiEngine,\n\t});\n\n\tasync function highlight(\n\t\tcode: string,\n\t\tlang = 'plaintext',\n\t\toptions: ShikiHighlighterHighlightOptions,\n\t\tto: 'hast' | 'html',\n\t) {\n\t\tconst resolvedLang = langAlias[lang] ?? lang;\n\t\tconst loadedLanguages = highlighter.getLoadedLanguages();\n\n\t\tif (!isSpecialLang(lang) && !loadedLanguages.includes(resolvedLang)) {\n\t\t\ttry {\n\t\t\t\tawait highlighter.loadLanguage(resolvedLang as BundledLanguage);\n\t\t\t} catch (_err) {\n\t\t\t\tconst langStr =\n\t\t\t\t\tlang === resolvedLang ? `\"${lang}\"` : `\"${lang}\" (aliased to \"${resolvedLang}\")`;\n\t\t\t\tconsole.warn(`[Shiki] The language ${langStr} doesn't exist, falling back to \"plaintext\".`);\n\t\t\t\tlang = 'plaintext';\n\t\t\t}\n\t\t}\n\n\t\tcode = code.replace(/(?:\\r\\n|\\r|\\n)$/, '');\n\n\t\tconst themeOptions = Object.values(themes).length ? { themes } : { theme };\n\t\tconst inline = options?.inline ?? false;\n\n\t\treturn highlighter[to === 'html' ? 'codeToHtml' : 'codeToHast'](code, {\n\t\t\t...themeOptions,\n\t\t\tdefaultColor: options.defaultColor,\n\t\t\tlang,\n\t\t\t// NOTE: while we can spread `options.attributes` here so that Shiki can auto-serialize this as rendered\n\t\t\t// attributes on the top-level tag, it's not clear whether it is fine to pass all attributes as meta, as\n\t\t\t// they're technically neither meta nor parsed from Shiki's `parseMetaString` API.\n\t\t\tmeta: options?.meta ? { __raw: options?.meta } : undefined,\n\t\t\ttransformers: [","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/withastro/astro/blob/52e6c34790cc8ac4e69e6135ace06049867e5c4a/packages/internal-helpers/src/shiki.ts#L180-L216","documentation":"Astro's shared Shiki highlighter helper (used for Markdown code fences and the `<Code />` component) resolves language aliases, then tries `highlighter.loadLanguage()` when the language isn't already loaded (packages/internal-helpers/src/shiki.ts:198). If loading throws — the id isn't a bundled Shiki language — it prints this console.warn and highlights the block as plaintext instead. Nothing fails; the code block still renders, just without tokens. The message distinguishes aliases, so `\"ts\" (aliased to \"typescript\")`-style output tells you exactly which id failed.","triggerScenarios":"Passing a `lang` that is neither a special lang (plaintext/text/html) nor a key/alias in Shiki's bundled languages: a Markdown fence like ```foo, `<Code lang=\"jsx-like\">`, or a custom grammar id that was never registered via `markdown.shikiConfig.langs`. It also fires when a language was excluded from the highlighter bundle (shikiConfig `langs` narrowed to a subset) but appears in a code fence.","commonSituations":"Typos in fence languages (`js` vs `jss`, `hs` vs `haskell`); using an unofficial language id from another highlighter (Prism aliases like `cxx` or `node`); fence tags that aren't languages at all (```title=..., or a stray ```console when the intended language differs); registering custom TextMate grammars in shikiConfig but referencing them by file path instead of the registered id.","solutions":["Correct the language id to one Shiki bundles — check the id against Shiki's bundled-languages list (e.g. 'typescript', 'tsx', 'python'), or the alias you assumed (e.g. 'js'→javascript works, 'javacript' does not).","If you need a non-bundled language, register a TextMate grammar under `markdown.shikiConfig.langs` in astro.config and reference the fence by that registered id.","If plaintext is acceptable, set the fence to ```text (or omit the lang) to silence the warn intentionally.","If warnings come from third-party Markdown you don't control, wrap code blocks with `<Code>` after normalizing lang, or filter fences in a rehype plugin before they reach Shiki."],"exampleFix":"```md\n<!-- before -->\n```haskell2\nmain = putStrLn \"hi\"\n```\n\n<!-- after -->\n```haskell\nmain = putStrLn \"hi\"\n```\n```","handlingStrategy":"validation","validationCode":"// validate fence languages against Shiki's bundled set before highlighting\nimport { bundledLanguages, codeToHtml } from 'shiki';\nconst isKnownLang = (lang: string) =>\n  lang === 'text' || lang === 'plaintext' || lang === 'html' || lang in bundledLanguages;\n\nconst lang = 'tsx';\nif (!isKnownLang(lang)) {\n  console.warn(`Skipping highlight for unknown language: ${lang}`);\n}","typeGuard":"import type { BundledLanguage } from 'shiki';\nimport { bundledLanguages } from 'shiki';\nconst isBundledLanguage = (l: string): l is BundledLanguage => l in bundledLanguages;","tryCatchPattern":null,"preventionTips":["Fence code blocks with exact Shiki ids/aliases (typescript, ts, py, bash) — check the Shiki languages reference when unsure rather than guessing.","For custom languages, register the TextMate grammar in `markdown.shikiConfig.langs` and fence by the id you registered, keeping content-source and highlighter config in sync.","If content comes from users or CMS data, normalize/whitelist `lang` before it reaches Markdown so one bad fence doesn't spray warnings across every dev build.","Use `text` fences deliberately for output/console samples instead of guessing ids like 'console' or 'shell'."],"tags":["shiki","syntax-highlighting","markdown","code-fence","fallback","language-alias"],"backgroundTag":"unknown-syntax-language-id","analyzedSha":"52e6c34790cc8ac4e69e6135ace06049867e5c4a","analyzedAt":"2026-08-18T18:48:03.901Z","contentChangedAt":"2026-08-18T18:48:03.901Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}