FyroxEngine/Fyrox · error

TransformStack pop failure.

Error message

TransformStack pop failure.

What it means

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.

Solutions

  1. Make every push have exactly one matching pop on all code paths (including early returns)
  2. Use a scope/guard pattern so pops are automatic
  3. Audit custom widget draw implementations for push/pop pairing

Example fix

// before
ctx.push(...) ; if done { return; } ctx.pop();
// after
ctx.push(...);
let result = compute();
ctx.pop(); // pop before any return
return result;
Defensive patterns

Strategy: validation

Prevention

When it happens

Trigger: 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.

Common situations: Hand-written custom widget rendering; conditional drawing paths that push but return before popping; refactored draw routines with duplicated pop calls.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of FyroxEngine/Fyrox@76c91aad8e (2026-09-10). Data as JSON: /api/errors/416317c7f68a3be7. Report an issue: GitHub.

Appendix: source

Thrown at fyrox-ui/src/draw.rs:804

        self.stack.len()
    }

    #[inline]
    pub fn is_empty(&self) -> bool {
        self.stack.is_empty()
    }

    #[inline]
    pub fn content(&self) -> Vec<Matrix3<f32>> {
        self.stack.clone()
    }

    #[inline]
    pub fn pop(&mut self) {
        if let Some(top) = self.stack.pop() {
            self.transform = top;
        } else {
            Log::err("TransformStack pop failure.")
        }
    }
}

#[derive(Debug, Clone, PartialEq, Default)]
pub struct RenderData {
    pub vertex_buffer: Vec<Vertex>,
    pub triangle_buffer: Vec<TriangleDefinition>,
    pub command_buffer: Vec<Command>,
}

impl Display for RenderData {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("RenderData")
            .field("Vertices Count: ", &self.vertex_buffer.len())
            .field("Triangles Count: ", &self.triangle_buffer.len())
            .field("Commands Count: ", &self.command_buffer.len())
            .finish()

View on GitHub (pinned to 76c91aad8e)