{"record":{"id":"9e9aa27b6a89bc0b","repo":"BabylonJS/Babylon.js","slug":"invalid-engine-unable-to-create-a-canvas","errorCode":null,"errorMessage":"Invalid engine. Unable to create a canvas.","messagePattern":"Invalid engine\\. Unable to create a canvas\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/dev/gui/src/2D/controls/colorpicker.pure.ts","lineNumber":223,"sourceCode":"\r\n    private _drawCircle(centerX: number, centerY: number, radius: number, context: ICanvasRenderingContext) {\r\n        context.beginPath();\r\n        context.arc(centerX, centerY, radius + 1, 0, 2 * Math.PI, false);\r\n        context.lineWidth = 3;\r\n        context.strokeStyle = \"#333333\";\r\n        context.stroke();\r\n        context.beginPath();\r\n        context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);\r\n        context.lineWidth = 3;\r\n        context.strokeStyle = \"#ffffff\";\r\n        context.stroke();\r\n    }\r\n\r\n    private _createColorWheelCanvas(radius: number, thickness: number): ICanvas {\r\n        // Shoudl abstract platform instead of using LastCreatedEngine\r\n        const engine = EngineStore.LastCreatedEngine;\r\n        if (!engine) {\r\n            throw new Error(\"Invalid engine. Unable to create a canvas.\");\r\n        }\r\n        const canvas = engine.createCanvas(radius * 2, radius * 2);\r\n        const context = canvas.getContext(\"2d\");\r\n        const image = context.getImageData(0, 0, radius * 2, radius * 2);\r\n        const data = image.data;\r\n\r\n        const color = this._tmpColor;\r\n        const maxDistSq = radius * radius;\r\n        const innerRadius = radius - thickness;\r\n        const minDistSq = innerRadius * innerRadius;\r\n\r\n        for (let x = -radius; x < radius; x++) {\r\n            for (let y = -radius; y < radius; y++) {\r\n                const distSq = x * x + y * y;\r\n\r\n                if (distSq > maxDistSq || distSq < minDistSq) {\r\n                    continue;\r\n                }\r","sourceCodeStart":205,"sourceCodeEnd":241,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/gui/src/2D/controls/colorpicker.pure.ts#L205-L241","documentation":"ColorPicker._createColorWheelCanvas needs an engine-owned 2D canvas (engine.createCanvas) to draw the color wheel image. It falls back to EngineStore.LastCreatedEngine, and when no engine exists at all it throws because no canvas can be created.","triggerScenarios":"Creating/showing a ColorPicker control in a headless or engine-less context — e.g. building GUI controls before EngineFactory/Engine is created, after engine.dispose(), or in a pure/DOM-only environment where LastCreatedEngine is null.","commonSituations":"Unit-testing GUI controls without a Babylon engine; instantiating the GUI before scene/engine initialization; using the pure (non-scene) build in Node; disposal-order bugs where the engine is gone but the GUI is still drawn.","solutions":["Ensure a Babylon engine is created (new Engine(canvas, ...) / EngineFactory.CreateAsync) before adding a ColorPicker to the GUI.","Check EngineStore.LastCreatedEngine is not null before constructing controls that draw canvas imagery.","If the engine was disposed, recreate it or remove the GUI before disposal.","For headless tests, stub/provide a mock engine exposing createCanvas and 2D context APIs."],"exampleFix":"// before\nconst adt = AdvancedDynamicTexture.CreateFullscreenUI(\"ui\"); // no engine created yet\nconst picker = new ColorPicker();\n\n// after\nconst engine = new Engine(canvas, true);\nconst scene = new Scene(engine);\nconst adt = AdvancedDynamicTexture.CreateFullscreenUI(\"ui\", true, scene);\nconst picker = new ColorPicker();","handlingStrategy":"type-guard","validationCode":"import { EngineStore } from \"@babylonjs/core/Engines/engineStore\";\nif (!EngineStore.LastCreatedEngine) {\n    throw new Error(\"Create a Babylon engine before using ColorPicker\");\n}\nconst picker = new ColorPicker();","typeGuard":"function hasEngine(e: unknown): e is { createCanvas(w: number, h: number): { getContext(c: \"2d\"): CanvasRenderingContext2D } } {\n    return !!e && typeof (e as any).createCanvas === \"function\";\n}","tryCatchPattern":"try {\n    gui.addControl(new ColorPicker());\n} catch (e) {\n    if (e instanceof Error && e.message.includes(\"Invalid engine\")) {\n        console.error(\"No Babylon engine available for canvas drawing:\", e);\n    } else {\n        throw e;\n    }\n}","preventionTips":["Always create the engine (and scene) before constructing any GUI controls.","Check EngineStore.LastCreatedEngine in app bootstrap before GUI init.","Never dispose the engine while the GUI is still attached; dispose GUI/ADT first.","In tests/headless environments, install a mock engine that provides createCanvas."],"tags":["engine","canvas","gui","initialization-order"],"backgroundTag":"engine-not-initialized","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}