{"record":{"id":"416317c7f68a3be7","repo":"FyroxEngine/Fyrox","slug":"transformstack-pop-failure","errorCode":null,"errorMessage":"TransformStack pop failure.","messagePattern":"TransformStack pop failure\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"fyrox-ui/src/draw.rs","lineNumber":804,"sourceCode":"        self.stack.len()\n    }\n\n    #[inline]\n    pub fn is_empty(&self) -> bool {\n        self.stack.is_empty()\n    }\n\n    #[inline]\n    pub fn content(&self) -> Vec<Matrix3<f32>> {\n        self.stack.clone()\n    }\n\n    #[inline]\n    pub fn pop(&mut self) {\n        if let Some(top) = self.stack.pop() {\n            self.transform = top;\n        } else {\n            Log::err(\"TransformStack pop failure.\")\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Default)]\npub struct RenderData {\n    pub vertex_buffer: Vec<Vertex>,\n    pub triangle_buffer: Vec<TriangleDefinition>,\n    pub command_buffer: Vec<Command>,\n}\n\nimpl Display for RenderData {\n    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n        f.debug_struct(\"RenderData\")\n            .field(\"Vertices Count: \", &self.vertex_buffer.len())\n            .field(\"Triangles Count: \", &self.triangle_buffer.len())\n            .field(\"Commands Count: \", &self.command_buffer.len())\n            .finish()","sourceCodeStart":786,"sourceCodeEnd":822,"githubUrl":"https://github.com/FyroxEngine/Fyrox/blob/76c91aad8eca488ce527b1af707be8b3b24ad72d/fyrox-ui/src/draw.rs#L786-L822","documentation":"Drawing UI uses a transform stack: DrawingContext::push saves the current transform and pop restores it. Popping an empty stack is an internal imbalance (more pops than pushes); the engine logs this error and leaves the transform unchanged to avoid a panic.","triggerScenarios":"Calling DrawingContext::pop without a matching prior push — e.g. custom widget draw code with a mis-ordered push/pop or early returns skipping a pop.","commonSituations":"Hand-written custom widget rendering; conditional drawing paths that push but return before popping; refactored draw routines with duplicated pop calls.","solutions":["Make every push have exactly one matching pop on all code paths (including early returns)","Use a scope/guard pattern so pops are automatic","Audit custom widget draw implementations for push/pop pairing"],"exampleFix":"// before\nctx.push(...) ; if done { return; } ctx.pop();\n// after\nctx.push(...);\nlet result = compute();\nctx.pop(); // pop before any return\nreturn result;","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pair every DrawingContext::push with exactly one pop on all paths","Pop before early returns in custom draw code","Use a guard struct whose Drop calls pop to guarantee balance"],"tags":["ui","drawing","stack-underflow"],"backgroundTag":"internal-invariant-violation","analyzedSha":"76c91aad8eca488ce527b1af707be8b3b24ad72d","analyzedAt":"2026-09-10T16:04:01.633Z","contentChangedAt":"2026-09-10T16:04:01.633Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}