STL Repair & Watertight Checker

Paste an ASCII STL or Wavefront OBJ mesh and get a plain-language diagnosis: degenerate and duplicate triangles, coincident vertices, non-manifold and open edges, flipped faces and shell count — then export the repaired, outward-facing mesh. Everything runs locally in your browser.

Try:
Repair report

About this tool

Slicers are unforgiving: a model that looks perfect in a 3D viewer can still refuse to slice because two triangles overlap, one face points inward, or a hairline crack runs along a seam. This tool reads a mesh as ASCII STL or Wavefront OBJ text, tells you exactly which of those problems it has, fixes the ones it can, and reports whether the result is finally watertight.

The repair pass does five things, each of which you can turn off:

Then it measures the result: triangle and vertex counts, non-manifold edges, open boundary edges, shell count, watertight yes/no, surface area, volume, and the bounding box. Everything runs locally in your browser — the mesh is never uploaded anywhere.

Worked example

A tetrahedron whose base face was exported wound the wrong way:

solid tetra
facet normal 0 0 0
outer loop
vertex 0 0 0
vertex 1 0 0
vertex 0 1 0
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 0 0 0
vertex 1 0 0
vertex 0 0 1
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 0 0 0
vertex 0 0 1
vertex 0 1 0
endloop
endfacet
facet normal 0 0 0
outer loop
vertex 1 0 0
vertex 0 1 0
vertex 0 0 1
endloop
endfacet
endsolid tetra

With the default settings the report comes back as:

STL repair report
=================

Input
  Format                  ASCII STL
  Solid name              tetra
  Triangles               4
  Distinct vertices       4

Problems found
  Degenerate triangles    0
  Duplicate triangles     0
  Coincident vertices     0
  Non-manifold edges      0
  Open (boundary) edges   0
  Flipped triangles       3
  Disconnected shells     1
  Watertight              no

Repairs applied
  Vertices welded         0
  Degenerate removed      0
  Duplicates removed      0
  Triangles re-wound      1
  Shells turned outward   0
  Holes filled            0 (0 triangles added)
  Fragments removed       0 (0 triangles dropped)

Result
  Triangles               4
  Distinct vertices       4
  Non-manifold edges      0
  Open (boundary) edges   0
  Disconnected shells     1
  Watertight              yes
  Surface area            2.366025
  Volume                  0.166667
  Bounding box            1 x 1 x 1
  Bounds                  min 0 0 0 / max 1 1 1

Three edges disagreed about which way round the surface went, one face was to blame, and after re-winding it the solid is watertight with a volume of 1/6. Switch Return to Repaired mesh (STL) to get the corrected file instead of the report, or to Report as JSON to feed the same numbers into a script.

What it does not do

FAQ

What does "watertight" actually mean here?

A mesh is reported as watertight when every edge is shared by exactly two triangles that traverse it in opposite directions. That means no open boundary edges, no edges shared by three or more faces, and no neighbouring faces that disagree about which side is out. It is the property a slicer needs in order to decide what is inside the solid and what is outside.

My mesh looks closed but reports thousands of open edges. Why?

Almost always the weld tolerance is too small for the file's precision. STL writes each triangle's corners independently, often rounded to six or seven digits, so two faces that should share a corner end up a fraction of a unit apart and the edge between them never pairs up. Raise the weld tolerance — try 0.001 for a model measured in millimetres — and run it again. The "Vertices welded" line tells you how many corners the tolerance merged.

Why is the volume shown as "n/a"?

Volume is only reported when the repaired mesh is closed. An open surface does not enclose a region, so any number would be meaningless — the same triangles could be read as enclosing almost anything. Close the mesh (enable hole filling, or raise the weld tolerance) and the volume appears. Surface area and the bounding box are always reported, closed or not.

What is the difference between a flipped triangle and an inside-out model?

A flipped triangle disagrees with its immediate neighbours, so it shows up as a count under "Flipped triangles" and is re-wound individually. An inside-out model is internally consistent — every face agrees with every neighbour — but the whole shell faces the wrong way. That is detected from the enclosed volume's sign and fixed by turning the entire shell, which is what the "Shells turned outward" line counts.

Can I feed it an OBJ file?

Yes. The format is auto-detected from the text: solid/facet/vertex lines are read as ASCII STL, and v/f lines as Wavefront OBJ. OBJ polygons are fan-triangulated, and OBJ materials, UVs and vertex normals are dropped — STL stores raw triangles only. Output is always STL.

Does my model get uploaded anywhere?

No. The whole repair runs as WebAssembly inside this page, so the mesh text never leaves your device and no network request is made with it. The same code is available offline through the command-line tool.

Developer & Automation Access

Run it from the terminal

Same engine as this page, headless — via the gizza CLI:

gizza tool stl-repair "solid part
facet normal 0 0 0
outer loop
vertex 0 0 0
vertex 1 0 0
vertex 0 1 0
endloop
endfacet
endsolid part"

New to the CLI? Get gizza →

Open it by URL

Pre-fill and auto-run this tool with query parameters — the names match the API/CLI:

https://gizza.ai/tools/stl-repair/?stl=solid%20part%0Afacet%20normal%200%200%200%0Aouter%20loop%0Avertex%200%200%200%0Avertex%201%200%200%0Avertex%200%201%200%0Aendloop%0Aendfacet%0Aendsolid%20part&output=report&weld_tolerance=0.000001&remove_degenerate=true&remove_duplicates=true&fix_winding=true&fill_holes=true&keep_largest_shell=true&stl_encoding=ascii

Machine-readable descriptor: tool.json — title + parameters JSON Schema for agents.