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

  1. Check that draw_func did not leave the cairo context in an error state before finishing the stream
  2. Ensure finish_output_stream() is only called once per surface
  3. Validate that width/height passed to SvgSurface::for_stream are positive and finite
  4. 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

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


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)