{"record":{"id":"e24ddd2f3d3dfc77","repo":"DevToys-app/DevToys","slug":"error-monaco-editor-library-isn-t-loaded","errorCode":null,"errorMessage":"Error : Monaco Editor library isn't loaded.","messagePattern":"Error : Monaco Editor library isn't loaded\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/app/dev/DevToys.Blazor/Assets/javascript/monacoEditor.ts","lineNumber":43,"sourceCode":"    // create a new instance of Monaco Editor.\n    public static create(\n        id: string,\n        options: monaco.editor.IStandaloneEditorConstructionOptions,\n        override: monaco.editor.IEditorOverrideServices,\n        dotNetObjRef: DotNet.DotNetObject): void {\n        if (options == null) {\n            options = {};\n        }\n\n        const oldEditor = MonacoEditor.getStandaloneCodeEditor(id, true);\n        if (oldEditor != null) {\n            options.value = oldEditor.getValue();\n            MonacoEditor.editors.splice(MonacoEditor.editors.findIndex(item => item.id == id), 1);\n            oldEditor.dispose();\n        }\n\n        if (typeof monaco === \"undefined\") {\n            throw new Error(\"Error : Monaco Editor library isn't loaded.\");\n        }\n\n        // Enable semantic tokens provider\n        (options as any)[\"semanticHighlighting.enabled\"] = true;\n\n        const newEditor = monaco.editor.create(document.getElementById(id), options, override);\n        MonacoEditor.editors.push({\n            id: id,\n            editor: newEditor,\n            dotNetObjRef: dotNetObjRef,\n            isDiffEditor: false\n        });\n    }\n\n    // create a new instance of Diff Monaco Editor.\n    public static createDiffEditor(\n        id: string,\n        options: monaco.editor.IStandaloneDiffEditorConstructionOptions,","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/DevToys-app/DevToys/blob/7e12df8448aa1f6aec4a8736b3e06a1c90530715/src/app/dev/DevToys.Blazor/Assets/javascript/monacoEditor.ts#L25-L61","documentation":"Thrown by MonacoEditor.create() after it has already located and disposed any pre-existing editor for the given id. The guard `typeof monaco === \"undefined\"` fires when the global `monaco` symbol was never defined, meaning the AMD loader (require([...]) in the static block) has not yet finished pulling in vs/editor/editor.main, or the load failed outright. Because the check sits after the destructive dispose() of the old editor, hitting it also discards the previous editor's value. Monaco is loaded asynchronously via requirejs, so any create() call that races ahead of that async load triggers this.","triggerScenarios":"Calling MonacoEditor.create(...) from a Blazor JS interop before the static block's `require([\"vs/editor/editor.main\"])` AMD callback resolves; the monaco-editor static assets under `_content/DevToys.Blazor/wwwroot/lib/monaco-editor/min/vs` being absent so require() fails silently; a Content-Security-Policy that blocks the vs/loader script; the page being offline or the dev server not serving the wwwroot assets.","commonSituations":"First render of a MonacoEditor Razor component on a cold start where JS init loses the race with component OnAfterRender; a publish/build that did not copy the monaco-editor lib folder; upgrading the monaco-editor npm package so the require.config path no longer matches the installed layout; running behind a strict CSP without allowing the app scheme origin.","solutions":["Verify the monaco assets exist at the served path: open _content/DevToys.Blazor/wwwroot/lib/monaco-editor/min/vs/loader.js in the browser and confirm 200 OK.","Make create() wait on the loader: convert require([...]) into a Promise and `await` it inside create()/createDiffEditor() before the typeof check.","Confirm require.config paths.vs matches the actual folder under wwwroot (it currently points at .../lib/monaco-editor/min/vs).","Check the browser console for AMD load errors and relax CSP (script-src) for the monaco vs path if it is being blocked.","As a safety net, call create() from OnAfterRenderAsync only after a small JS readiness check that resolves when `typeof monaco !== \"undefined\"`."],"exampleFix":"// before\nstatic {\n    require.config({ paths: { \"vs\": \"_content/DevToys.Blazor/wwwroot/lib/monaco-editor/min/vs\" } });\n    require([\"vs/editor/editor.main\"]); // fire-and-forget, async\n}\n// ...\nif (typeof monaco === \"undefined\") {\n    throw new Error(\"Error : Monaco Editor library isn't loaded.\");\n}\n\n// after\nprivate static _loaded: Promise<void> | null = null;\nprivate static ensureLoaded(): Promise<void> {\n    if (typeof monaco !== \"undefined\") return Promise.resolve();\n    if (!MonacoEditor._loaded) {\n        MonacoEditor._loaded = new Promise<void>((resolve, reject) => {\n            require.config({ paths: { \"vs\": \"_content/DevToys.Blazor/wwwroot/lib/monaco-editor/min/vs\" } });\n            require([\"vs/editor/editor.main\"], () => resolve(), (e: any) => reject(e));\n        });\n    }\n    return MonacoEditor._loaded;\n}\npublic static async create(id, options, override, dotNetObjRef): Promise<void> {\n    await MonacoEditor.ensureLoaded();\n    // ... existing body without the typeof throw\n}","handlingStrategy":"validation","validationCode":"// Run this before invoking MonacoEditor.create from .NET interop.\n// Resolves true only when the global monaco object is ready.\npublic static isReady(): boolean {\n    return typeof monaco !== \"undefined\" && !!monaco.editor;\n}\n\n// From Blazor OnAfterRenderAsync:\n//   bool ready = await js.InvokeAsync<bool>(\"MonacoEditor.isReady\");\n//   if (!ready) { await js.InvokeVoidAsync(\"MonacoEditor.ensureLoaded\"); }","typeGuard":"declare const monaco: any;\nfunction isMonacoLoaded(): monaco is typeof monaco {\n    return typeof monaco !== \"undefined\" && typeof monaco.editor === \"object\";\n}","tryCatchPattern":"try {\n    MonacoEditor.create(id, options, override, dotNetObjRef);\n} catch (e) {\n    if (e instanceof Error && /isn't loaded/.test(e.message)) {\n        // monaco assets missing or still loading — await ensureLoaded() then retry once\n        await MonacoEditor.ensureLoaded();\n        MonacoEditor.create(id, options, override, dotNetObjRef);\n    } else {\n        throw e;\n    }\n}","preventionTips":["Expose ensureLoaded() as a Promise around require([\"vs/editor/editor.main\"], cb) and await it before every create/createDiffEditor.","Confirm the published assets at _content/DevToys.Blazor/wwwroot/lib/monaco-editor/min/vs return 200 in CI smoke tests.","Gate the MonacoEditor Razor component's OnAfterRenderAsync interop on a readiness probe rather than firing on first render.","Pin the monaco-editor npm version and assert the require.config path matches the installed folder layout in a build check."],"tags":["monaco-editor","blazor","javascript","async-loading","race-condition"],"backgroundTag":null,"analyzedSha":"7e12df8448aa1f6aec4a8736b3e06a1c90530715","analyzedAt":"2026-08-13T10:27:33.924Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}