flxzt/rnote · error

Downcasting Svg surface content failed, Err

Error message

Downcasting Svg surface content failed, Err: {e:?}

What it means

Thrown by Svg::gen_with_cairo when the Box<dyn Any> returned by finish_output_stream() cannot be downcast to Vec<u8>. The stream backing the SVG surface must be the Vec<u8> originally supplied; a mismatch means the surface's stream is not the expected type.

Solutions

  1. Ensure the SvgSurface was created with SvgSurface::for_stream(width, height, Vec::new()) and the stream was never swapped
  2. Downcast to the actual stream type used (e.g. File) if a custom stream was set
  3. Use downcast_ref first to inspect the concrete type when debugging

Example fix

// before
.downcast::<Vec<u8>>().map_err(|e| anyhow::anyhow!("Downcasting Svg surface content failed, Err: {e:?}"))?
// after
match stream.downcast::<Vec<u8>>() {
    Ok(bytes) => bytes,
    Err(any) => anyhow::bail!("unexpected stream type: {:?}", any.type_id()),
}
Defensive patterns

Strategy: type-guard

Type guard

fn is_vec_stream(any: &Box<dyn Any>) -> bool { any.is::<Vec<u8>>() }

Try / catch

let bytes = stream.downcast::<Vec<u8>>().map_err(|e| anyhow::anyhow!("stream type mismatch: {:?}", e.type_id()))?;

Prevention

When it happens

Trigger: finish_output_stream() returns a Box<dyn Any> whose inner type differs from the Vec<u8> given to SvgSurface::for_stream — e.g. the stream was replaced via set_custom_output_stream or the surface came from another source.

Common situations: Refactoring code to use a custom output stream without updating the downcast, or reusing generic surface-finish helper code on a surface not created with a Vec<u8> stream.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

Thrown at crates/rnote-engine/src/svg.rs:139

        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,
        })
    }

    /// Generate an Svg with piet, using the `piet_cairo` backend and cairo's SvgSurface.
    ///

View on GitHub (pinned to bbc5354502)