docs/solutions/logic-errors/2026-04-17-code-block-browser-highlight-must-match-server-output.md
The standalone code block demo could hydrate into a broken client tree even though the editor logic itself was fine.
The bad sample was the Python code block on /blocks/code-block-demo.
[CODE_HIGHLIGHT] Could not highlight with Highlight.js for language "python". Falling back to plaintext.next state; stale dev output obscured the real failurePatch the provided lowlight instance inside @platejs/code-block before
highlighting Python, so kits can stay unchanged.
ensureStablePythonGrammar(lowlight, effectiveLanguage);
Files:
The vendored grammar is adapted from the older Highlight.js Python definition
that still uses beginKeywords and ASCII identifier matching instead of the
newer unicodeRegex + match[] path that explodes in the Turbopack browser
bundle.
The patch mutates the caller-provided lowlight instance once, overriding only
the Python grammar and its aliases:
lowlight.register('python', pythonBrowserSafe);
lowlight.registerAlias('python', ['py', 'gyp', 'ipython']);
That keeps createLowlight(all) in app kits untouched while making server and
browser share the same stable Python tokenizer.
Regression coverage:
The bug was not "Python cannot be server-rendered." The bug was "the current Highlight.js 11 Python grammar compiles differently in the Turbopack browser bundle than it does on the server."
The bad path came from the newer grammar features:
unicodeRegex: truematch: [...] multi-class rules for def and classIn the browser bundle, Highlight.js core rebuilt that into a huge character class with an out-of-order range, so Python highlighting threw before the editor finished normalizing.
By swapping only Python to the older browser-safe grammar, both server and browser render the same highlighted tree again, and the hydration mismatch goes away without sacrificing Python syntax highlighting.
bun test packages/code-block/src/lib/setCodeBlockToDecorations.spec.ts
bun test packages/code-block/src/lib/BaseCodeBlockPlugin.inputRules.spec.tsx
bun test ./apps/www/src/__tests__/package-integration/code-block/current-kit.slow.tsx
pnpm install
pnpm turbo build --filter=./packages/code-block --filter=./apps/www
pnpm turbo typecheck --filter=./packages/code-block --filter=./apps/www
pnpm lint:fix
Browser proof:
browser-use load of http://localhost:3001/blocks/code-block-demo
shows no hydration error and no [CODE_HIGHLIGHT] warnings for Pythoneditor.plugins.code_block.options.lowlight.highlight('python', ...)
succeeds in the live page and returns highlighted nodes``` in a reset paragraph still creates a code_block with
one code_line and no leftover backticks