{"record":{"id":"8e8f80c26262454c","repo":"BabylonJS/Babylon.js","slug":"unsupported-stencil-opfail-mode-opfail","errorCode":null,"errorMessage":"Unsupported stencil OpFail mode: ${opFail}.","messagePattern":"Unsupported stencil OpFail mode: (.+?)\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/dev/core/src/Engines/Native/nativeHelpers.ts","lineNumber":253,"sourceCode":"    switch (opFail) {\r\n        case Constants.KEEP:\r\n            return _native.Engine.STENCIL_OP_FAIL_S_KEEP;\r\n        case Constants.ZERO:\r\n            return _native.Engine.STENCIL_OP_FAIL_S_ZERO;\r\n        case Constants.REPLACE:\r\n            return _native.Engine.STENCIL_OP_FAIL_S_REPLACE;\r\n        case Constants.INCR:\r\n            return _native.Engine.STENCIL_OP_FAIL_S_INCR;\r\n        case Constants.DECR:\r\n            return _native.Engine.STENCIL_OP_FAIL_S_DECR;\r\n        case Constants.INVERT:\r\n            return _native.Engine.STENCIL_OP_FAIL_S_INVERT;\r\n        case Constants.INCR_WRAP:\r\n            return _native.Engine.STENCIL_OP_FAIL_S_INCRSAT;\r\n        case Constants.DECR_WRAP:\r\n            return _native.Engine.STENCIL_OP_FAIL_S_DECRSAT;\r\n        default:\r\n            throw new Error(`Unsupported stencil OpFail mode: ${opFail}.`);\r\n    }\r\n}\r\n\r\nexport function getNativeStencilDepthFail(depthFail: number): number {\r\n    switch (depthFail) {\r\n        case Constants.KEEP:\r\n            return _native.Engine.STENCIL_OP_FAIL_Z_KEEP;\r\n        case Constants.ZERO:\r\n            return _native.Engine.STENCIL_OP_FAIL_Z_ZERO;\r\n        case Constants.REPLACE:\r\n            return _native.Engine.STENCIL_OP_FAIL_Z_REPLACE;\r\n        case Constants.INCR:\r\n            return _native.Engine.STENCIL_OP_FAIL_Z_INCR;\r\n        case Constants.DECR:\r\n            return _native.Engine.STENCIL_OP_FAIL_Z_DECR;\r\n        case Constants.INVERT:\r\n            return _native.Engine.STENCIL_OP_FAIL_Z_INVERT;\r\n        case Constants.INCR_WRAP:\r","sourceCodeStart":235,"sourceCodeEnd":271,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/core/src/Engines/Native/nativeHelpers.ts#L235-L271","documentation":"getNativeStencilOpFail translates a Babylon.js stencil fail-op constant (Constants.KEEP, ZERO, REPLACE, INCR, DECR, INVERT, INCR_WRAP, DECR_WRAP) into the corresponding Babylon Native engine enum. If the opFail value passed to applyStencil is not one of these known constants, the switch hits default and throws. It is a guard against passing invalid or unsupported stencil state to the native backend.","triggerScenarios":"Calling engine.applyStencil(faceMode, opFail, ...) with an opFail value that is not one of the Constants stencil ops, e.g. a raw integer that doesn't match any case, undefined/null, or a value from a different API.","commonSituations":"Hand-rolling stencil state with magic numbers instead of Constants enums; porting WebGL code to Babylon Native where an op constant is out of range; a typo or stale constant from another Babylon version.","solutions":["Pass opFail from Constants (e.g. Constants.KEEP, Constants.INCR, Constants.DECR_WRAP) instead of a raw number.","Log/validate opFail before calling applyStencil to confirm it is a defined Constants stencil op.","If a needed op is genuinely missing, check Babylon.js version and update, or open an issue to add the native mapping."],"exampleFix":"// before\nengine.applyStencil(true, 0x150, 0x150, 0x150); // raw GL enums\n// after\nengine.applyStencil(true, Constants.INCR_SAT, Constants.INCR_SAT, Constants.INCR_SAT);","handlingStrategy":"validation","validationCode":"const OPS = [BABYLON.Constants.KEEP, BABYLON.Constants.ZERO, BABYLON.Constants.REPLACE, BABYLON.Constants.INCR, BABYLON.Constants.DECR, BABYLON.Constants.INVERT, BABYLON.Constants.INCR_WRAP, BABYLON.Constants.DECR_WRAP];\nif (!OPS.includes(opFail)) throw new RangeError(`opFail must be a Constants stencil op, got ${opFail}`);\nengine.applyStencil(face, opFail, depthFail, opPass);","typeGuard":"function isStencilOp(v: unknown): v is number {\n  const C = BABYLON.Constants;\n  return typeof v === 'number' && [C.KEEP, C.ZERO, C.REPLACE, C.INCR, C.DECR, C.INVERT, C.INCR_WRAP, C.DECR_WRAP].includes(v);\n}","tryCatchPattern":"try {\n  engine.applyStencil(face, opFail, depthFail, opPass);\n} catch (e) {\n  if (String(e.message).startsWith('Unsupported stencil OpFail')) {\n    console.warn('Bad opFail, falling back to KEEP', opFail);\n    engine.applyStencil(face, BABYLON.Constants.KEEP, depthFail, opPass);\n  } else throw e;\n}","preventionTips":["Always pass Constants.* stencil enums, never raw WebGL GLenum numbers.","Centralize stencil state setup in one helper that validates ops.","Add a unit test asserting each applyStencil argument is a defined Constants value."],"tags":["babylonjs","stencil","native-engine","invalid-enum"],"backgroundTag":"unsupported-enum-value","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}