flxzt/rnote · error
finishing piet context failed, Err
Error message
finishing piet context failed, Err: {e:?} What it means
In image generation via cairo, the piet CairoRenderContext's finish() failed after running the caller-supplied draw function. finish() flushes and validates all piet rendering state; an error here means the draw function left the piet context in a bad state or the underlying cairo backend reported an error, so no valid image could be produced.
Solutions
- Inspect the wrapped error `{e:?}` to find which piet/cairo operation failed inside draw_func.
- Validate stroke geometry (no NaN/infinite coordinates, sane transform) before drawing.
- Ensure the draw function completes all piet operations and does not misuse save/restore or clips.
- Update piet-cairo/cairo crates in case of a backend bug.
Example fix
// before
draw_func(&mut piet_cx)?;
piet_cx.finish().map_err(|e| anyhow!("finishing piet context failed, Err: {e:?}"))?;
// after
draw_func(&mut piet_cx).context("draw function failed")?;
piet_cx.finish().with_context(|| format!("finishing piet context failed, Err: {e:?}"))?; Defensive patterns
Strategy: try-catch
Validate before calling
// Rust: ensure bounds and scale are sane before generating the image
fn gen_params_ok(bounds: kurbo::Rect, scale: f64) -> bool {
bounds.is_finite() && bounds.width() > 0.0 && bounds.height() > 0.0 && scale.is_finite() && scale > 0.0
} Type guard
fn finite_bounds(r: &kurbo::Rect) -> bool {
r.x0.is_finite() && r.x1.is_finite() && r.y0.is_finite() && r.y1.is_finite()
} Try / catch
match Image::gen_with_piet(draw_fn, bounds, scale) {
Ok(img) => ...,
Err(e) => log::error!("image generation failed: {e:#}"),
} Prevention
- Ensure draw functions balance save/restore and produce finite geometry (no NaN/inf).
- Validate bounds and scale before invoking generation.
- Keep piet/cairo dependencies updated to avoid known backend finish() bugs.
When it happens
Trigger: Calling the public gen_with_piet entry with a draw_func that triggers a cairo error (e.g. invalid path/clip state, unsupported operations) or leaves the piet context unflushed/invalid; cairo surface errors surfacing at finish().
Common situations: Rendering a stroke whose geometry produces an invalid cairo path; exporting a bitmap of a document containing strokes that hit cairo backend limits; bugs in custom draw functions passed to gen_with_piet.
Related errors
- Make piet image in BitmapImage draw impl failed, Err
- finishing piet context failed, Err
- Building text layout failed, Err
- Finishing Svg surface output stream failed, Err
- on-conflict behaviour is still Ask after prompting the user.
AI-assisted analysis of flxzt/rnote@bbc5354502 (2026-09-08).
Data as JSON: /api/errors/3b500b20713295b1.
Report an issue: GitHub.
Appendix: source
Thrown at crates/rnote-engine/src/image.rs:385
pixel_width: width_scaled,
pixel_height: height_scaled,
// cairo renders to bgra8-premultiplied, but we convert it to rgba8-premultiplied
memory_format: ImageMemoryFormat::R8g8b8a8Premultiplied,
})
}
/// Generates an image with a provided closure that draws onto a [piet_cairo::CairoRenderContext].
pub fn gen_with_piet<F>(draw_func: F, bounds: Aabb, image_scale: f64) -> anyhow::Result<Self>
where
F: FnOnce(&mut piet_cairo::CairoRenderContext) -> anyhow::Result<()>,
{
let cairo_draw_fn = move |cairo_cx: &cairo::Context| -> anyhow::Result<()> {
let mut piet_cx = piet_cairo::CairoRenderContext::new(cairo_cx);
// Apply the draw function
draw_func(&mut piet_cx)?;
piet_cx
.finish()
.map_err(|e| anyhow::anyhow!("finishing piet context failed, Err: {e:?}"))?;
Ok(())
};
Self::gen_with_cairo(cairo_draw_fn, bounds, image_scale)
}
}
pub(super) fn convert_image_bgra_to_rgba(_width: u32, _height: u32, mut bytes: Vec<u8>) -> Vec<u8> {
for src in bytes.as_chunks_mut::<4>().0 {
let (blue, green, red, alpha) = (src[0], src[1], src[2], src[3]);
src[0] = red;
src[1] = green;
src[2] = blue;
src[3] = alpha;
}
bytes
}
View on GitHub (pinned to bbc5354502)