WIP: Guard tagHighlighter style() against null/undefined tags #20

Closed
falko-apheris wants to merge 1 commit from fix/tags-not-iterable-when-lezer-common-duplicated into main
falko-apheris commented 2026-03-10 13:44:20 +01:00 (Migrated from github.com)

Problem

When @lezer/common is accidentally instantiated multiple times (e.g. by a bundler such as Vite's esbuild pre-bundler creating duplicate module instances), NodeProp IDs from one instance can collide with prop IDs from another. This causes getStyleTags() to return an object whose .tags property is undefined instead of a Rule, which then crashes the highlighter with:

CodeMirror plugin crashed: TypeError: tags is not iterable
  at HighlightStyle.style (index.js:284:29)
  at highlightTags (index.js:301:33)
  at HighlightBuilder.highlightRange (index.js:388:22)
  at highlightTree (index.js:329:13)
  at TreeHighlighter.buildDeco (index.js:1784:13)

This is a known real-world issue reported in:

The root cause is always the same: duplicate @lezer/common instances leading to colliding prop IDs, which means node.type.prop(ruleNodeProp) can return an unrelated object (without a .tags array) instead of a Rule.

Fix

Make tagHighlighter's style() function defensive by treating a null/undefined tags argument as an empty array, so the plugin degrades gracefully (no highlighting) instead of crashing the entire editor.

Also widens the Highlighter interface's style() signature to readonly Tag[] | null to reflect this.

This does not prevent the underlying bundler misconfiguration but it stops the editor from becoming completely non-functional when it occurs.

## Problem When `@lezer/common` is accidentally instantiated multiple times (e.g. by a bundler such as Vite's esbuild pre-bundler creating duplicate module instances), `NodeProp` IDs from one instance can collide with prop IDs from another. This causes `getStyleTags()` to return an object whose `.tags` property is `undefined` instead of a `Rule`, which then crashes the highlighter with: ``` CodeMirror plugin crashed: TypeError: tags is not iterable at HighlightStyle.style (index.js:284:29) at highlightTags (index.js:301:33) at HighlightBuilder.highlightRange (index.js:388:22) at highlightTree (index.js:329:13) at TreeHighlighter.buildDeco (index.js:1784:13) ``` This is a known real-world issue reported in: - Issue #19 (TypeError: tags is not iterable) - Issue #14 (CodeMirror plugin crashed: TypeError: t is not iterable) - https://discuss.codemirror.net/t/highlighting-that-seems-ignored-in-cm6/4320 The root cause is always the same: duplicate `@lezer/common` instances leading to colliding prop IDs, which means `node.type.prop(ruleNodeProp)` can return an unrelated object (without a `.tags` array) instead of a `Rule`. ## Fix Make `tagHighlighter`'s `style()` function defensive by treating a `null`/`undefined` tags argument as an empty array, so the plugin degrades gracefully (no highlighting) instead of crashing the entire editor. Also widens the `Highlighter` interface's `style()` signature to `readonly Tag[] | null` to reflect this. This does **not** prevent the underlying bundler misconfiguration but it stops the editor from becoming completely non-functional when it occurs.
marijnh commented 2026-03-10 13:48:25 +01:00 (Migrated from github.com)

This won't solve the problem (you'll still get confused highlighting), and when you have duplicated packages, in a web context, you really want to know, and fix it, rather than suppress the errors. So this is not something I want to merge.

This won't solve the problem (you'll still get confused highlighting), and when you have duplicated packages, in a web context, you _really_ want to know, and fix it, rather than suppress the errors. So this is not something I want to merge.
falko-apheris commented 2026-03-10 13:55:35 +01:00 (Migrated from github.com)

@marijnh thanks, I was about to extend this with more than just the agent generated text, but thanks for clarifying, this is now breaking codemirror for a while and I'm trying to fix it.

@marijnh thanks, I was about to extend this with more than just the agent generated text, but thanks for clarifying, this is now breaking codemirror for a while and I'm trying to fix it.
falko-apheris commented 2026-03-10 13:57:11 +01:00 (Migrated from github.com)

@marijnh Could you give me a hint what you mean with

you really want to know, and fix it

I'm not sure what to fix, or rather where this error originates from

@marijnh Could you give me a hint what you mean with > you really want to know, and fix it I'm not sure what to fix, or rather where this error originates from
marijnh commented 2026-03-10 14:02:06 +01:00 (Migrated from github.com)

Your package manager is installing multiple copies of packages. The reason you want to fix this is that it'll make you users download a lot more JavaScript than they need, and it'll break some libraries (including Lezer and CodeMirror). You either have some incompatible versions in your dependencies (look for 0.x versions of CodeMirror or Lezer packages), or you use a dumb tool like yarn, which is really bad at deduplicating packages. Clearing your package lock and reinstalling from scratch often helps.

Your package manager is installing multiple copies of packages. The reason you want to fix this is that it'll make you users download a lot more JavaScript than they need, and it'll break some libraries (including Lezer and CodeMirror). You either have some incompatible versions in your dependencies (look for 0.x versions of CodeMirror or Lezer packages), or you use a dumb tool like yarn, which is really bad at deduplicating packages. Clearing your package lock and reinstalling from scratch often helps.
falko-apheris commented 2026-03-10 14:13:19 +01:00 (Migrated from github.com)

Awesome that really helped I updated my package.json and now the problem is gone 🎉

    "pnpm": {
		"overrides": {
			"@lezer/common": "^1.5.1"
		}
	}

The cause
@codemirror/language@6.12.2 requires @lezer/common ^1.5.0, but @lezer/highlight@1.2.3 only declares ^1.3.0. pnpm installs both 1.4.0 and 1.5.1 side-by-side.

this results in

CodeMirror plugin crashed: TypeError: s is not iterable
    at Rc.style (DCgjx8Rh.js:11:75203)
    at AA (DCgjx8Rh.js:11:75337)
    at PA.highlightRange (DCgjx8Rh.js:11:75905)
    at OA (DCgjx8Rh.js:11:75451)
    at a3.buildDeco (DCgjx8Rh.js:11:99718)
    at a3.update (DCgjx8Rh.js:11:99568)
    at Ef.update (DCgjx8Rh.js:7:20783)
    at Q.updatePlugins (DCgjx8Rh.js:10:9450)
    at Q.update (DCgjx8Rh.js:10:7705)
    at Q.dispatchTransactions (DCgjx8Rh.js:10:5618)
image
Awesome that really helped I updated my `package.json` and now the problem is gone :tada: ``` "pnpm": { "overrides": { "@lezer/common": "^1.5.1" } } ``` The cause @codemirror/language@6.12.2 requires @lezer/common ^1.5.0, but @lezer/highlight@1.2.3 only declares ^1.3.0. pnpm installs both 1.4.0 and 1.5.1 side-by-side. this results in ``` CodeMirror plugin crashed: TypeError: s is not iterable at Rc.style (DCgjx8Rh.js:11:75203) at AA (DCgjx8Rh.js:11:75337) at PA.highlightRange (DCgjx8Rh.js:11:75905) at OA (DCgjx8Rh.js:11:75451) at a3.buildDeco (DCgjx8Rh.js:11:99718) at a3.update (DCgjx8Rh.js:11:99568) at Ef.update (DCgjx8Rh.js:7:20783) at Q.updatePlugins (DCgjx8Rh.js:10:9450) at Q.update (DCgjx8Rh.js:10:7705) at Q.dispatchTransactions (DCgjx8Rh.js:10:5618) ``` <img width="1327" height="358" alt="image" src="https://github.com/user-attachments/assets/ff0d329e-38cc-4619-94c6-11b0798be46f" />

Pull request closed

Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lezer/highlight!20
No description provided.