{"record":{"id":"d2fbed59bafca6d6","repo":"phaserjs/phaser","slug":"cannot-override-final-property-k-set-class-i","errorCode":null,"errorMessage":"cannot override final property '${k}', set Class.ignoreFinals = true to skip","messagePattern":"cannot override final property '(.+?)', set Class\\.ignoreFinals = true to skip","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/utils/Class.js","lineNumber":109,"sourceCode":"        {\n            //  If Extends is used, we will check its prototype to see if the final variable exists.\n\n            var parent = extend || ctor;\n\n            if (hasNonConfigurable(parent.prototype, k))\n            {\n                //  Just skip the final property\n                if (Class.ignoreFinals)\n                {\n                    continue;\n                }\n\n                //  We cannot re-define a property that is configurable=false.\n                //  So we will consider them final and throw an error. This is by\n                //  default so it is clear to the developer what is happening.\n                //  You can set ignoreFinals to true if you need to extend a class\n                //  which has configurable=false; it will simply not re-define final properties.\n                throw new Error('cannot override final property \\'' + k + '\\', set Class.ignoreFinals = true to skip');\n            }\n\n            Object.defineProperty(ctor.prototype, k, def);\n        }\n        else\n        {\n            ctor.prototype[k] = definition[k];\n        }\n    }\n}\n\n/**\n * Applies the given `mixins` to the prototype of `myClass`.\n *\n * @function mixin\n * @ignore\n * @param {Object} myClass The constructor object to mix into.\n * @param {Object|Array<Object>} mixins The mixins to apply to the constructor.","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/phaserjs/phaser/blob/41be1e462bc600064e498cba370bfa8c5c055a22/src/utils/Class.js#L91-L127","documentation":"Thrown by Phaser.Class's internal extend() helper when a definition tries to redefine a prototype property that already exists on the parent (or the ctor) with configurable:false. The framework refuses to silently redefine a 'final' property and points the developer at the opt-out. This is the ES5 class-system equivalent of a sealed/final member. The error message names the offending property (k) so you know which member collided.","triggerScenarios":"Calling `new Phaser.Class({ Extends: SomePhaserClass, someFinalProp: ... })` where SomePhaserClass.prototype.someFinalProp was defined via Object.defineProperty with configurable:false. Also when a Mixin introduces a property that clashes with a non-configurable one on the target. Common with internal Phaser classes that define properties as accessors or with explicit descriptors.","commonSituations":"Extending an internal Phaser GameObject or system class and overriding a property that Phaser declared as final. Mixing two Phaser classes whose prototypes both define the same non-configurable key. Upgrading Phaser versions where a previously-overridable property became non-configurable. Using a minifier/transpiler that emits Object.defineProperty with configurable:false for class fields.","solutions":["If the override is intentional and safe, set `Phaser.Class.ignoreFinals = true` globally before defining the class (this skips redefinition of final properties, so the child keeps the parent's version).","Rename the colliding property in your definition so it does not shadow the final one.","If you need new behavior, override the method that USES the property rather than the property itself, or add a differently-named property and patch the consuming methods.","Reset ignoreFinals to false afterward if you only want the override for one class definition."],"exampleFix":"// before\nvar MyImage = new Phaser.Class({\n  Extends: Phaser.GameObjects.Image,\n  // 'texture' is non-configurable on the parent\n  texture: 'player'\n});\n\n// after (opt-out, parent's property kept)\nPhaser.Class.ignoreFinals = true;\nvar MyImage = new Phaser.Class({ Extends: Phaser.GameObjects.Image /* no texture override */ });\nPhaser.Class.ignoreFinals = false;","handlingStrategy":"validation","validationCode":"function canOverrideFinal(parentCtor, key) {\n  var desc = Object.getOwnPropertyDescriptor(parentCtor.prototype, key);\n  return !desc || desc.configurable !== false;\n}\n\nfunction safeClass(definition) {\n  var parent = definition.Extends;\n  if (parent) {\n    for (var k in definition) {\n      if (k === 'Extends' || k === 'Mixins' || k === 'initialize') continue;\n      if (!canOverrideFinal(parent, k)) {\n        Phaser.Class.ignoreFinals = true;\n        break;\n      }\n    }\n  }\n  var cls = new Phaser.Class(definition);\n  Phaser.Class.ignoreFinals = false;\n  return cls;\n}","typeGuard":"function isFinalProperty(parentCtor, key) {\n  var desc = Object.getOwnPropertyDescriptor(parentCtor.prototype, key);\n  return !!desc && desc.configurable === false;\n}","tryCatchPattern":"var prev = Phaser.Class.ignoreFinals;\ntry {\n  Phaser.Class.ignoreFinals = true;\n  MyClass = new Phaser.Class(definition);\n} finally {\n  Phaser.Class.ignoreFinals = prev;\n}","preventionTips":["Audit parent prototypes with Object.getOwnPropertyDescriptor before overriding in Phaser.Class.","Prefer overriding methods that consume a property rather than the property itself.","Keep ignoreFinals scoped: set true, define the class, reset to false in a finally block.","Avoid non-configurable properties in your own base classes if you intend them to be overridable."],"tags":["class","inheritance","prototype","configurable","oop"],"backgroundTag":null,"analyzedSha":"41be1e462bc600064e498cba370bfa8c5c055a22","analyzedAt":"2026-08-13T04:23:39.729Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}