Why fillets break at corners, and the dumb idea that fixed mine
24 September 2026
Round one bottom edge of a box. Leave the edge next to it square. Put a 3 mm radius on the vertical corner between them. Any CAD program does this without blinking, and for a week the one I am building in the browser could not.
It was always the same corner. The rounded edge would bend inward just before the corner and come back out, like it was dodging something. The untouched edge next to it grew a small wedge that looked like a car bumper. On the bottom face there was a patch of rounding nobody asked for. Three separate models, three reports, one bug.
If you only print things, you can skip to the part about testing, because that is where the lessons are. If you are curious how a fillet gets made at all, the first half explains why corners are where it goes wrong.
How I was making fillets
A fillet is the round you put on an edge instead of leaving it sharp. (There is a longer post on when to fillet and when to chamfer for printing, and the short version is: chamfer the bottom, round the rest.) On a pad that you extrude from a sketch, the obvious way to round the top edge is to shrink the outline. At the very top the outline is pulled in by the full radius, a little lower it is pulled in less, and at the bottom of the fillet it is not pulled in at all. Stack those outlines up and connect them, and you have a rounded rim.
For a 3 mm radius my editor stacked 33 of those outlines, 0.094 mm apart. It works beautifully when every edge is rounded. It works less well when only some are, because then you shrink the whole outline anyway and cut away the parts that should have stayed square.
The corners are where it falls apart. At a rounded corner between a picked edge and an unpicked one, the fillet has to stop somewhere, and "somewhere" was a pile of special rules. Fade the depth across the arc. Carry it around the arc and fade it along the next edge instead. Patch the leftover crumple with a separately built blend. Clip the mask so the fade does not leave a sheet with no thickness. Every rule fixed the last screenshot and made the next one. At one point a 0/0 in the fade quietly produced a NaN, which threw away the entire rounded band and rebuilt the rim without it, and the only visible sign was a bar of 100 stripes on the top face.
The idea that worked
I said I wanted it simple: if an edge is rounded, cut the rounding along the whole length of that edge. Do not think about corners. If the next edge is rounded too, it cuts its own groove, and the corner is whatever the two grooves leave.
So now each treated edge gets its own cutter. The cutter is the shape a fillet removes, a square with a quarter circle taken out of it, pushed along the full edge. For a straight edge it runs on to where the edge would meet its neighbour if the corner were sharp, and a bit past that on an obtuse corner, so it leaves cleanly through the next face. Then it is subtracted from the part. That's it.
The corner that had been failing for a week now works without a single line about corners. The straight cutter crosses the rounded vertical corner, trims it, and dies exactly where the corner meets the untouched edge. The volume came out exact where I could check it by hand: two 2 mm chamfers on a 40 by 25 by 8 mm block leave 7840 mm³, which is 8000 minus 2 × 40 × 2. The old method gave 7848.87.
Two cases do need a second cutter. A rounded corner between two rounded edges gets one swept around its own arc, or the two straight grooves meet in a crease. And an inside corner, like the notch of an L, gets one that turns around the vertex the way a rolling ball would. Without it the two flat ends of the grooves left a small spike standing up between them.
Building parts to find the rest
Unit tests told me each feature worked alone. So I sat down and built about 30 parts the way someone would: an enclosure with a shell and a USB cutout, an L bracket with holes, a knob, a flange with a bolt circle, a tray with two pockets, a star, a loft from a circle to a square, a twisted pad. Five of them came out wrong, and every one of those five was two features meeting.
The star had 86 non-manifold edges. That is a mesh where some edges are shared by four triangles instead of two, and a slicer either refuses it or guesses. The inside-corner cutter had its flat ends lying exactly on the ends of the straight cutters, and two faces in the same plane is what confuses a boolean. Turning the corner cutter 2 degrees past each end fixed it.
A 90 mm disc with a 1 mm chamfer came out with a ring of tabs round the rim. The disc's wall is a 96-sided polygon. The cutter was built from a 48-point outline, so every other corner of the wall stuck out past the cutter and kept its sharp edge. You would print that and wonder why the chamfer looks like a castle.
A 20 by 20 by 10 mm cube twisted 45 degrees should weigh exactly 4000 mm³, because twisting turns each slice without changing it. Mine weighed 4078. Each flat wall was one long quad per slice, and a quad twisted out of its plane folds along its diagonal, bulging outward. Splitting the walls into short pieces before twisting got it to 3997.
The loft did the same thing between its two profiles and drew a few hundred creases up the sides. And a rounded boss on a leaning wall had two bad edges where a helper piece I used to glue it into the wall had sides lying exactly on the boss's sides. Same lesson as the star.
What I test now
Every part has to export as one closed, watertight body. Where there is a number I can work out on paper, the volume has to land on it, because a volume that is 2% off is a shape that is wrong somewhere you are not looking. And each of those five parts is now a test, which I ran against the old build first to make sure it fails there. A test that passes on the broken version is decoration.
The editor is still hidden while I work through this list. Pocket rims and text still use the old shrinking outlines, and they are next.