🐛 Fix legacy path migration crash on paths without points (#12357)

The legacy-6 migration read the rect of each path from its points and
checked whether the width or height was close to zero. A path with
missing or empty points has no rect, so the check got nil and threw a
NullPointerException. The migration then failed on every load of that
file, and get-team-shared-files returned 500 for the whole team, so the
"Add library" modal could not open.

Treat a missing rect like a degenerate one and rebuild the selrect and
points from the path content.

Closes #12343

AI-assisted-by: claude-opus-5-5
This commit is contained in:
Eva Marco 2026-10-15 13:23:54 +02:00 committed by GitHub
parent a53481c3b7
commit 0d9b1c48fc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 46 additions and 2 deletions

View File

@ -223,8 +223,10 @@
[data _]
(letfn [(fix-line-paths [shape]
(if (= (:type shape) :path)
(let [{:keys [width height]} (grc/points->rect (:points shape))]
(if (or (mth/almost-zero? width) (mth/almost-zero? height))
;; A path with missing or empty points has no rect; rebuild
;; its geometry from the content as for line-like paths.
(let [{:keys [width height] :as rect} (grc/points->rect (:points shape))]
(if (or (nil? rect) (mth/almost-zero? width) (mth/almost-zero? height))
(let [selrect (path.segment/content->selrect (:content shape))
points (grc/rect->points selrect)
transform (gmt/matrix)

View File

@ -605,3 +605,45 @@
data' (cfm/migrate-data data migration-id)]
(t/is (= [child-id] (get-in data' [:components component-id :objects main-id :shapes])))))
(defn- make-path-shape
[shape-id]
(cts/setup-shape {:id shape-id
:type :path
:content [{:command :move-to :params {:x 10 :y 20}}
{:command :line-to :params {:x 110 :y 70}}]}))
(t/deftest migration-legacy-6-repairs-paths-without-points
(let [migration-id "legacy-6"
page-id (uuid/next)
shape-id (uuid/next)
shape (make-path-shape shape-id)]
(doseq [points [nil []]]
(let [data {:pages-index {page-id {:objects {shape-id (assoc shape :points points)}}}}
data' (cfm/migrate-data data migration-id)
shape' (get-in data' [:pages-index page-id :objects shape-id])]
(t/is (= (:points shape) (:points shape'))
(str "points rebuilt from content when they were " (pr-str points)))
(t/is (= (:selrect shape) (:selrect shape'))
"selrect rebuilt from content")))))
(t/deftest migration-legacy-6-runs-through-file-migration
;; A file saved before version 6 runs every migration from legacy-6 on,
;; and the whole chain must succeed for the file to load.
(let [migration-id "legacy-6"
shape-id (uuid/next)
file (ctf/make-file {:name "Legacy path without points"})
page-id (first (get-in file [:data :pages]))
shape (-> (make-path-shape shape-id)
(assoc :points []))
file (-> file
(dissoc :migrations)
(assoc :version 5)
(assoc-in [:data :pages-index page-id :objects shape-id] shape))
file' (cfm/migrate-file file (delay {}))]
(t/is (contains? (:migrations file') migration-id) "migration id persisted")
(t/is (= 4 (count (get-in file' [:data :pages-index page-id :objects shape-id :points])))
"path points repaired before schema validation")))