Error: Multiple instances of @codemirror/state

I have a typescript setup like follows:
The problem occurs when i import the codemirror-lang-homescript package, which was created according to the language feature example repository.
I get following error (using Vite as my build tool)

index.js:2004 Uncaught Error: Unrecognized extension value in extension set ([object Object]). This sometimes happens because multiple instances of @codemirror/state are loaded, breaking instanceof checks.
    at inner (index.js:2004:23)
    at inner (index.js:1979:17)
    at inner (index.js:2005:13)
    at inner (index.js:1979:17)
    at inner (index.js:2005:13)
    at inner (index.js:1979:17)
    at flatten (index.js:2008:5)
    at Configuration.resolve (index.js:1916:25)
    at EditorState.create (index.js:2741:43)
    at HmsEditor.svelte:82:32

    import { EditorState, EditorView, basicSetup } from '@codemirror/basic-setup'
    import { indentWithTab } from '@codemirror/commands'
    import { keymap } from '@codemirror/view'
    import { linter, lintGutter, type Diagnostic } from '@codemirror/lint'
    import { createEventDispatcher, onMount } from 'svelte'
    // import { tags } from "@lezer/highlight";
    // import { HighlightStyle, syntaxHighlighting } from "@codemirror/language";
    // import { completeFromList } from "@codemirror/autocomplete";

    // TODO: move local files to separate repository
    import { Homescript } from 'codemirror-lang-homescript'
    import { oneDark } from './oneDark'
    import { lintHomescriptCode } from '../../../homescript'
    import { createSnackbar } from '../../../global'

    const dispatch = createEventDispatcher()

    // Specifies whether the editor should register a CTRL+S catcher
    // This catcher is intended to prevent the browser's default action
    // However, the catcher also emits a change event when the key combination is pressed
    export let registerCtrlSCatcher = false

    // Represents the editor's value
    export let code = ''
    $: setCode(code)

    function setCode(cd: string) {
        if (editor === undefined || editor.state.doc.toString() === cd) return
                changes: { from: 0, to: editor.state.doc.length, insert: cd },

    // Will later be bound to the target of the CodeMirror editor
    let editorDiv: HTMLElement

    let editor: EditorView

    // eslint-disable-next-line no-undef
    let timer: NodeJS.Timeout

    const HMSlinter = linter(async () => {
        let diagnostics: Diagnostic[] = []

        try {
            const result = await lintHomescriptCode(code, [])
            diagnostics = => {
                const lines = code.split('\n')

                let startPos: number = e.location.column - 1 // Starts at -1 because the last line does not end with '\n'
                for (let lineIndex = 0; lineIndex < e.location.line - 1; lineIndex++) {
                    startPos += lines[lineIndex].length + 1

                return Object.create({
                    from: startPos,
                    to: startPos,
                    severity: e.errorType === 'Panic' ? 'warning' : 'error',
                    message: `${e.errorType}: ${e.message}`,
                    source: 'HMS',
        } catch (err) {
            $createSnackbar(`Failed to lint: ${err}`)

        return diagnostics

    onMount(() => {
        if (registerCtrlSCatcher)
            document.addEventListener('keydown', e => {
                if (e.ctrlKey && e.key === 's') {
                    dispatch('update', code)
        editor = new EditorView({
            state: EditorState.create({
                extensions: [
                    // Linting
                    // Emit the `update` event 500 ms after the last keystroke
                    EditorView.updateListener.of(v => {
                        if (v.docChanged) {
                            if (timer) clearTimeout(timer)
                            timer = setTimeout(() => {
                                dispatch('update', code)
                            }, 500)
                    // Update the component code on every change
                    EditorView.updateListener.of(v => {
                        if (v.docChanged) {
                            code = editor.state.doc.toString()
                doc: code,
            parent: editorDiv,

            editor.state.changeByRange((range) => ({
                changes: [{ from: range.from, insert: "switch('id', on)" }],
                range: EditorSelection.range(range.from + 2, + 2),
1 Like

Clearing your package lock and reinstalling your dependencies often helps with this.

Thank you for your time,
Unfortunately, I’ve tried both of these methods which still yields no success.

Furthermore, the setup works completely fine if i copy the files inside the language-repo’s dist
directory to the location of the Codemirror setup where I include them locally.

Something like this completely works.

 import { Homescript } from './index.js'

You had it symlinked? (Your original message reads like there might be some text missing.) Yeah, npm won’t deduplicate across linked dependencies.

Thank you for your support, I found the issue.
It was caused because I was using the @codemirror/basic-setup dependency (which is obviously deprecated).

I’m hitting this error as well, using Vite as my bundler (Tried the above mentioned suggestion). I’m using a vue-codemirror dependency to help do a lot of the vue setup. It’s worth noting this exact config had no issues while I was using Webpack. Curious if it has to do with how Vite handles module resolution?

Here is the error:

Uncaught Error: Unrecognized extension value in extension set. This sometimes happens because multiple instances of @codemirror/state are loaded, breaking instanceof checks.

Here is the dependency list for @codemirror/state:

β”‚ β”œβ”€β”¬ @codemirror/autocomplete@6.4.1
β”‚ β”‚ └── @codemirror/state@6.2.0 deduped
β”‚ β”œβ”€β”¬ @codemirror/lang-css@6.0.2
β”‚ β”‚ └── @codemirror/state@6.2.0 deduped
β”‚ β”œβ”€β”¬ @codemirror/lang-javascript@6.1.4
β”‚ β”‚ └── @codemirror/state@6.2.0 deduped
β”‚ β”œβ”€β”¬ @codemirror/language@6.6.0
β”‚ β”‚ └── @codemirror/state@6.2.0 deduped
β”‚ β”œβ”€β”€ @codemirror/state@6.2.0
β”‚ └─┬ @codemirror/view@6.9.0
β”‚   └── @codemirror/state@6.2.0 deduped
β”œβ”€β”¬ @codemirror/theme-one-dark@6.1.0
β”‚ └── @codemirror/state@6.2.0 deduped
β”œβ”€β”¬ codemirror@6.0.1
β”‚ β”œβ”€β”¬ @codemirror/commands@6.2.1
β”‚ β”‚ └── @codemirror/state@6.2.0 deduped
β”‚ β”œβ”€β”¬ @codemirror/lint@6.1.1
β”‚ β”‚ └── @codemirror/state@6.2.0 deduped
β”‚ β”œβ”€β”¬ @codemirror/search@6.2.3
β”‚ β”‚ └── @codemirror/state@6.2.0 deduped
β”‚ └── @codemirror/state@6.2.0 deduped
└─┬ vue-codemirror@6.1.1
  └── @codemirror/state@6.2.0 deduped

Here is my pkg.json:

"codemirror": "^6.0.1",
"@codemirror/theme-one-dark": "^6.1.0",
"@codemirror/lang-html": "^6.4.0",
"vue-codemirror": "^6.1.1",

Happy to provide more info as well, keep hitting dead ends with this error.

For information, we hit the same problem when working on

The package was properly dedupe to a single version. But the configuration of the various packages mixes typescript module resolution of commonjs and esnext. The consequence was the inclusion by webpack of @codemirror/state as ESM (importing @codemirror/state/dist/index.js) and as commonJS (importing @codemirror/state/dist/index.cjs).
The solution for us was to ensure homogeneous module resolution.