flxzt/rnote · error
Finishing Svg surface output stream failed, Err
Error message
Finishing Svg surface output stream failed, Err: {e:?} What it means
Thrown by Svg::gen_with_cairo when cairo's SvgSurface::finish_output_stream() returns a cairo::Error. After all drawing on the SVG surface is done, cairo must flush and finish the backing stream; if the surface is already in an error state (e.g. from a failed earlier draw operation) or was finished twice, this call fails.
Solutions
- Check that draw_func did not leave the cairo context in an error state before finishing the stream
- Ensure finish_output_stream() is only called once per surface
- Validate that width/height passed to SvgSurface::for_stream are positive and finite
- Log the wrapped cairo::Error to identify the underlying cairo status
Example fix
// before
let content = String::from_utf8(*svg_surface.finish_output_stream().map_err(|e| anyhow::anyhow!("Finishing Svg surface output stream failed, Err: {e:?}"))?.downcast::<Vec<u8>>()?)?;
// after
let stream = svg_surface.finish_output_stream().map_err(|e| anyhow::anyhow!("Finishing Svg surface output stream failed, Err: {e:?}"))?;
let bytes = *stream.downcast::<Vec<u8>>().map_err(|e| anyhow::anyhow!("Downcasting failed: {e:?}"))?;
let content = String::from_utf8(bytes)?; Defensive patterns
Strategy: try-catch
Validate before calling
debug_assert!(bounds.extents()[0] > 0.0 && bounds.extents()[1] > 0.0);
Type guard
fn surface_healthy(s: &cairo::Surface) -> bool { s.status() == cairo::Status::Success } Try / catch
match svg_surface.finish_output_stream() {
Ok(stream) => { /* downcast and use bytes */ }
Err(e) => log::error!("svg stream finish failed: {e:?}"),
} Prevention
- Only finish each surface once
- Validate drawing bounds are positive and finite before creating surfaces
- Check cairo context status after draw operations in debug builds
When it happens
Trigger: Calling finish_output_stream() on an SvgSurface whose context recorded an error during draw_func, calling it twice on the same surface, or cairo marking the surface invalid (invalid dimensions, write failure to the backing stream).
Common situations: Drawing with invalid cairo state (e.g. negative/zero surface dimensions slipped through), double-finishing a surface reused for export, or memory/stream failures during large SVG exports in rnote.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- finishing piet context failed, Err
- Creating svg surface with dimensions
- Downcasting Svg surface content failed, Err
- finishing piet context failed, Err
- rendering rsvg document failed, Err
AI-assisted analysis of flxzt/rnote@bbc5354502 (2026-09-08).
Data as JSON: /api/errors/56218199c6addeb0.
Report an issue: GitHub.
Appendix: source
Thrown at crates/rnote-engine/src/svg.rs:135
anyhow::anyhow!(
"Creating svg surface with dimensions ({width}, {height}) failed, Err: {e:?}"
)
})?;
svg_surface.set_document_unit(cairo::SvgUnit::Px);
{
let cairo_cx = cairo::Context::new(&svg_surface)?;
// cairo only draws elements with positive coordinates, so we need to translate the content here
cairo_cx.translate(-bounds.mins[0], -bounds.mins[1]);
// apply the draw function
draw_func(&cairo_cx)?;
}
let content = String::from_utf8(
*svg_surface
.finish_output_stream()
.map_err(|e| {
anyhow::anyhow!("Finishing Svg surface output stream failed, Err: {e:?}")
})?
.downcast::<Vec<u8>>()
.map_err(|e| {
anyhow::anyhow!("Downcasting Svg surface content failed, Err: {e:?}")
})?,
)?;
let svg_data = rnote_compose::utils::remove_xml_header(&content);
let mut group = svg::node::element::Group::new().add(svg::node::Blob::new(svg_data));
// translate the content back to it's original position
group.assign(
"transform",
format!("translate({} {})", bounds.mins[0], bounds.mins[1]),
);
Ok(Self {
svg_data: rnote_compose::utils::svg_node_to_string(&group)?,
bounds,
})View on GitHub (pinned to bbc5354502)