Does my STL file have holes? Count the edges
The slicer refuses your file and says the mesh is open or non-manifold, and nothing on the screen tells you where the problem is or how big it is. There is a countable answer. Every number below is measured on the machine that wrote it and re-run by npm test before the page is published.
The short answer
A printable shell uses every edge exactly twice. An edge used once is part of a hole. Our closed test cube — a 10 mm cube converted from IGES — measures 12 triangles and 18 distinct edges, and every one of those 18 edges is shared by exactly two triangles. When one whole square face is removed, the same cube measures 10 triangles, 17 distinct edges, and exactly 4 edges used once. Those 4 edges are the boundary of the missing square: the hole is not a vague quality of the file, it is a list of edges you can name and count.
The one check: multiply by three, divide by two
Each triangle has 3 edges, so N triangles carry 3×N edge-uses. A closed mesh spends each edge on exactly two triangles, so a closed solid must satisfy distinct edges = 3×N ÷ 2. The test cube checks out from both directions: 12 triangles give 12 × 3 = 36 edge-uses, and 36 ÷ 2 = 18 distinct edges, with 0 used once. Run the same arithmetic on any mesh you are suspicious of: if the two sides do not meet, the difference is exactly the set of single-use edges, and each of them is a stretch of open boundary that the slicer cannot assign an inside or an outside to.
| Shell | Triangles | Edge-uses (3×N) | Distinct edges | Edges used once |
|---|---|---|---|---|
| Closed cube | 12 | 36 | 18 (36 ÷ 2) | 0 |
| Cube, one face removed | 10 | 30 | 17 | 4 |
Where the edge count separates hole from non-manifold
The count classifies every edge into three buckets, and each bucket means something different. Used once is an open boundary — the mesh stops, one side of the edge faces nothing, and that is what a hole is made of. Used twice is a normal shared edge, the only kind a closed solid may contain. Used three or more times is a non-manifold edge — more than two triangles claim the same edge, so the surface folds against itself and no consistent inside or outside exists there. The closed test cube measures 0 edges used once and 0 edges used three or more times; the open variant measures 4 used once and still 0 used three or more times, because removing a face cannot create the second defect. The two failures print differently in slicers but share one property: neither is introduced by the conversion, and neither is fixed by it.
What to do about it
The conversion triangulates and does not repair. Tessellation walks the surfaces the STEP file declares and writes each one out as triangles; it never invents a surface that is missing from the file, so a gap in the source arrives in the STL as the same gap. That fixes the order of operations for you: the repair belongs on the source side. Restore the missing face in the CAD model — or in the STEP file itself, if you are editing text — export again, and re-run the count. What you should not expect is to heal it afterwards one vertex at a time: a hole is not a misplaced point, it is a missing face, and STL-side editing moves vertices by hand at a cost the editing page measures. Once the source closes, convert it again on the front-page converter and the identity should hold: every edge used exactly twice.
One caution while you compare tools: a converter that promises to “fix” or “heal” meshes is not doing the same job as conversion, and a repaired mesh can differ from the source in ways the source never authorized. The honest position is the one this page takes — report the counts, tell you the shell is open, and leave the repair decision to you.
Why you will not find this count elsewhere
Of the three benchmark sites this project tracks — polyd.com, convert3d.org, imagetostl.com — none walks through a countable hole test. convert3d's STEP page is a compatibility table with no failure guidance at all. imagetostl's pages describe file formats in terms of vertices and faces without ever dividing by two. The closest any of them comes is a general blog list of five printing-mistake categories on polyd, where discontinuous edges and flat holes appear as one bullet among five, with no number attached that a reader could reproduce. The divide-by-two identity needs three numbers — 12, 36, 18 — and each of them is pinned to the test suite, which is what makes the check reproducible rather than advisory.
Where these numbers come from
- 12 triangles, 18 edges, every edge used exactly twice, 0 used once — measured on the project's own IGES test cube with the shipped engine (occt-import-js 0.0.23, a WebAssembly build of OpenCASCADE). The suite rebuilds the mesh, counts every edge use and checks the closed shell on every run.
- 10 triangles, 17 distinct edges, exactly 4 edges used once — produced by removing one whole planar face from that same measured cube and counting again. The four single-use edges are the four sides of the removed square; the diagonal edge that only the two removed triangles shared disappears entirely, which is why 18 drops to 17.
- 36 edge-uses ÷ 2 = 18, and 30 = 13 × 2 + 4 × 1 — the divide-by-two identity in both directions, checked against the same live counts rather than against constants.
- 12 triangles → 684 bytes — the binary STL identity 84 + 50 × triangles on the same cube, so the triangle count in the edge arithmetic can be confirmed from the file size alone.
npm test
The command above re-runs every number on this page. The short version of this check lives as check 2 on the verification page; the triangle counts behind it belong to the measured table on the front page; and the converter itself reports the triangle count your own file produces, in the tab, with nothing uploaded.