FyroxEngine/Fyrox · error

Unable to measure text due to unloaded fonts.

Error message

Unable to measure text due to unloaded fonts. {:?}.
{}

What it means

FormattedText::measure needs every font referenced by the text to be loaded; measuring with missing fonts would produce garbage metrics. If any font is absent it logs this error with the text and a per-font loading summary, and returns a zero-size measurement.

Solutions

  1. Wait for font resources to finish loading before building/measuring text widgets
  2. Verify font resource paths and that the resource load succeeded
  3. Check font_loading_summary() output to see which font failed and why
  4. Provide a fallback font that is always loaded

Example fix

// before
let size = formatted_text.measure();
// after
if formatted_text.are_fonts_loaded() {
    let size = formatted_text.measure();
} else {
    // retry next frame or log font_loading_summary()
}
Defensive patterns

Strategy: validation

Validate before calling

if !formatted_text.are_fonts_loaded() {
    // defer measuring / rendering until fonts load
} else {
    let size = formatted_text.measure();
}

Type guard

fn text_ready(ft: &FormattedText) -> bool { ft.are_fonts_loaded() }

Prevention

When it happens

Trigger: Calling measure (directly or via text-measuring during layout) when the UI's font resource is still loading, failed to load, or was never set.

Common situations: Referencing fonts by path that don't exist on disk; measuring on the first frame before async font loading finishes; deleted font resources in .rgs files; wrong resource path in theme.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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

Appendix: source

Thrown at fyrox-ui/src/formatted_text.rs:897

            if let Some(font) = run.font() {
                write!(result, "\nRun {:?}: {}", run.range, font.header().state).unwrap();
            }
        }
        result
    }

    pub fn measure_and_arrange(&mut self) -> Vector2<f32> {
        let size = self.measure();
        self.arrange(self.constraint);
        size
    }

    pub fn measure(&mut self) -> Vector2<f32> {
        let mut lines = std::mem::take(&mut self.lines);
        lines.clear();
        // Fail early if any font is not available.
        if !self.are_fonts_loaded() {
            Log::err(format!(
                "Unable to measure text due to unloaded fonts. {:?}.\n{}",
                self.text(),
                self.font_loading_summary(),
            ));
            return Vector2::default();
        }
        let constraint = Vector2::new(
            (self.constraint.x - (self.padding.left + self.padding.right)).max(0.0),
            (self.constraint.y - (self.padding.top + self.padding.bottom)).max(0.0),
        );
        let first_indent = self.line_indent.max(0.0);
        let normal_indent = -self.line_indent.min(0.0);
        let sink = WrapSink {
            lines: &mut lines,
            normal_width: constraint.x - normal_indent,
            first_width: constraint.x - first_indent,
        };
        if let Some(mask) = *self.mask_char {

View on GitHub (pinned to 76c91aad8e)