flxzt/rnote · error

Building piet text layout failed, Err

Error message

Building piet text layout failed, Err: {e:?}

What it means

build_text_layout uses a piet TextLayoutBuilder to lay out the text stroke; piet's build() returns a Result with a BuildError. Any layout failure (bad attributes, font issues, invalid ranges) is wrapped into this anyhow error. Callers like untransformed_size and cursor/selection APIs depend on it, so a failure here breaks all text measurement and editing.

Solutions

  1. Fix the root attribute error: ensure all font families in text_style resolve on this system
  2. Validate attribute ranges fit within the text length before building the layout
  3. Catch this error in callers and render fallback metrics or an error placeholder instead of propagating
  4. Verify fontconfig works (fc-list) on the target machine; install base fonts in containers/headless environments

Example fix

// before
let size = stroke.untransformed_size(&mut piet_cairo::CairoText::new(), text)?;
// after
let size = stroke.untransformed_size(&mut piet_cairo::CairoText::new(), text)
    .with_context(|| format!("text layout failed for {:?}", stroke.text_style.font_attrs()))?;
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure all font families resolve before building
for attr in &stroke.text_style.attributes {
    if let TextAttribute::FontFamily(f) = attr {
        if piet_text.font_family(f.as_str()).is_none() { return Err(anyhow!("font '{f}' unavailable")); }
    }
}

Try / catch

let size = stroke.untransformed_size(&mut piet_cairo::CairoText::new(), text)
    .context("text layout failed; check font availability and attribute ranges")?;

Prevention

When it happens

Trigger: Calling untransformed_size, lines, cursor_hittest_position, or get_selection_rects_for_cursors when the underlying layout build fails — typically because a TextAttribute references an unavailable font (see error 143) or an out-of-order/invalid range attribute.

Common situations: Text containing characters unsupported by the resolved font; attributes applied with ranges beyond text length; systems with broken fontconfig where piet cannot load any font.

Related errors


AI-assisted analysis of flxzt/rnote@bbc5354502 (2026-09-08). Data as JSON: /api/errors/b016caf3c044b034. Report an issue: GitHub.

Appendix: source

Thrown at crates/rnote-engine/src/strokes/textstroke.rs:284

        let mut ranged_text_attributes = self.ranged_text_attributes.clone();
        ranged_text_attributes.sort_unstable_by_key(|first| first.range.start);

        // Apply ranged attributes
        for (range, piet_attr) in ranged_text_attributes
            .into_iter()
            .filter_map(|ranged_attr| {
                Some((
                    ranged_attr.range,
                    ranged_attr.attribute.try_into_piet(piet_text).ok()?,
                ))
            })
        {
            text_layout_builder = text_layout_builder.range_attribute(range, piet_attr);
        }

        text_layout_builder
            .build()
            .map_err(|e| anyhow::anyhow!("Building piet text layout failed, Err: {e:?}"))
    }

    pub fn untransformed_size<T>(&self, piet_text: &mut T, text: String) -> anyhow::Result<Vector2>
    where
        T: piet::Text,
    {
        let text_layout = self.build_text_layout(piet_text, text)?;
        let size = text_layout.size();
        Ok(Vector2::new(size.width, size.height))
    }

    /// The cursors line metric relative to the textstroke bounds.
    pub fn lines<T>(&self, piet_text: &mut T, text: String) -> anyhow::Result<Vec<piet::LineMetric>>
    where
        T: piet::Text,
    {
        let text_layout = self.build_text_layout(piet_text, text)?;

View on GitHub (pinned to bbc5354502)