diff --git a/crates/vectordrawable/src/tests/strokes.rs b/crates/vectordrawable/src/tests/strokes.rs
--- a/crates/vectordrawable/src/tests/strokes.rs
+++ b/crates/vectordrawable/src/tests/strokes.rs
@@ -42,6 +42,15 @@ fn a_miter_limit_other_than_four_is_written() {
     assert_eq!(paths_of(&out.xml)[0].get("strokeMiterLimit"), Some("10"));
 }
 
+#[test]
+fn a_huge_miter_limit_is_written_as_a_finite_number() {
+    let (mut d, r) = stroked(StrokeAlign::Center);
+    d.get_mut(r).unwrap().stroke.miter_limit = 1e306;
+    let out = export(&d, &[r], Compat::BestEffort);
+    let v = paths_of(&out.xml)[0].get("strokeMiterLimit").unwrap().to_string();
+    assert!(v.parse::<f32>().unwrap().is_finite(), "{v}");
+}
+
 #[test]
 fn a_uniform_scale_scales_the_stroke_width() {
     let (mut d, r) = stroked(StrokeAlign::Center);
diff --git a/crates/vectordrawable/src/xml.rs b/crates/vectordrawable/src/xml.rs
--- a/crates/vectordrawable/src/xml.rs
+++ b/crates/vectordrawable/src/xml.rs
@@ -19,6 +19,9 @@ pub(crate) fn num(v: f64) -> String {
     if !v.is_finite() {
         return "0".into();
     }
+    // Android reads these as 32-bit floats, so clamp to that range; this also keeps the scaling
+    // below from overflowing to infinity.
+    let v = v.clamp(-f64::from(f32::MAX), f64::from(f32::MAX));
     let r = (v * 1000.0).round() / 1000.0;
     let s = format!("{r}");
     if s == "-0" { "0".into() } else { s }
