A thirteen-hour print that dies at layer 40 costs you a day and most of a spool. The frustrating part is that almost every one of those failures was already visible in the file before you pressed print — you just had to look at the right number, and no slicer shows it to you. This is a small free tool that looks at those numbers for you. It exists because I lost three prints in a week to problems that took under a second to detect once I knew what to measure.
Free, MIT licensed, no account and no telemetry. Two dependencies
(trimesh and numpy), Python 3.9 or newer.
Download the wheel (13 KB) Source tarball
pip install printcheck-0.1.1-py3-none-any.whl
Three commands:
printcheck preflight model.stl # is this orientation printable?
printcheck verify new.gcode --against known.gcode # did anything drift?
printcheck flatten "0.20mm Standard" --profiles-root ... --series ...
It exits 0 when clean and 1 when something fails, so you can put it in a
build script and have it stop a bad plate before it ever reaches the printer.
Both of these come from the same part — the cap of a filament waste container, downloaded from a model site. It killed two prints in a row, in two completely different ways.
The cap arrived as 5 × 227 × 140.1 mm: a five-millimetre-thin wall standing 140 mm tall. That's a 28:1 ratio. It wobbled, detached mid-print, and the nozzle dragged it around the plate, taking its plate-mate down with it — about 14 g of filament and an hour gone.
Nothing warned me. The dimensions were on screen the entire time and I read straight past them, because "5 × 227 × 140" doesn't look like a hazard until you divide it.
$ printcheck preflight cap.stl
cap.stl
size 5.0 x 227.0 x 140.12 mm
height/footprint 28.02:1 (140.12 mm tall on 5.0 mm)
[FAIL] Height/footprint ratio 28.02:1 exceeds 8.0:1 - this stands 140.12 mm
tall on a 5.0 mm footprint and is likely to detach and be dragged.
Over roughly 8:1 with no brim, stop and re-orient. Here it was a single rotation, and the print time even dropped slightly.
Here's the part I want to save you: laying it flat was not enough. The rotation put the cap horizontal, but it landed hollow-side-down — resting on a thin rim, with 109.4 cm² of flat underside floating three millimetres in mid-air.
The slicer did exactly what it was told and bridged all of it: 1,376 bridge blocks in the first five millimetres. The bridges collapsed, the nozzle dragged the wreckage, and the print died at Z 3–4 mm. Then the replacement died at the same height, for the same reason, because I'd concluded the problem was stringing and gone off to tune retraction.
One more 180° flip took that number from 109.4 cm² to 0.0, and bridge blocks from 1,376 to 4. It printed clean — 25 of 25 layers, 45.6 minutes — straight through the band that had killed both previous attempts.
$ printcheck preflight cap_flat.stl
flat underside in mid-air 109.39 cm2
[FAIL] 109.39 cm2 of flat underside is floating above the plate. The slicer
will bridge all of it and long bridges collapse. This usually means the
part is lying on the wrong face - try flipping it 180 degrees.
It also bins overhangs by angle, because faces at 60–75° from vertical genuinely need support, and it's worth knowing that before you decide you can get away without it.
The premise behind verify is that you already own a better specification than any
documentation: the gcode from a print that came out right. So compare against it.
$ printcheck verify new.gcode --against known-good.gcode
config: 2 of 565 keys differ from known-good.gcode
enable_support
known-good: 0
candidate: 1
per-object Z range (plate max Z hides a badly oriented part):
poop_chute.stl_id_0_copy_0 0.20 -> 162.60 mm
support vs overhang: 98% of overhang moves fall in Z bands that also contain
support (peak overhang band 80-100 mm has support).
Three checks, each of which caught something real:
EXCLUDE_OBJECT markers
the slicer already emits, it's unmissable: 140.20 before the fix, 5.00 after. That's proof rather than
inference.Overhang wall features
proves nothing — that classifies a perimeter, it doesn't say whether anything is underneath it. The
count sat at 1,439 with supports both on and off, and I wrongly concluded supports weren't doing
anything. Comparing the height distribution of support moves against overhang moves does
answer the question.inheritsThis one is narrower — it applies to QIDI Studio and the Orca / Bambu Studio family it forks — but it's the nastiest of the three, because everything appears to work.
When you pass a preset to the CLI as a file path, it does not resolve the preset's
inherits chain. It silently falls back to built-in defaults for every key the file
doesn't literally contain, and still reports Success.
One slice of mine came out with volumetric speed 2 instead of 24.5, acceleration 1000 instead of 20000,
travel 120 instead of 500, and the nozzle at 200 °C instead of 210 — 16 of 34 critical settings
wrong, print time inflated by 2.9×, and filament_usage_g reported as 0, which
turns out to be the tell-tale sign.
printcheck flatten walks the chain through the vendor index and merges it into one
self-contained file. It goes through the index rather than guessing filenames, because a preset's name
and its filename often differ — QIDI PLA Rapido@X4 lives in
QIDI PLA Rapido.json — and guessing fails on exactly the profiles that matter. It also
warns when the flattened result has no curr_bed_type, which quietly defaults the bed to
Cool Plate at 35 °C and guarantees PLA won't stick to a textured PEI sheet.
Only flatten is vendor-specific. preflight works on any STL, and
verify works with any slicer that emits a ; key = value config block —
PrusaSlicer, OrcaSlicer, Bambu Studio and their forks all do.
The thresholds came from one real part printed in three orientations with three known outcomes: the
28:1 version that detached, the flat-but-wrong-face version that collapsed twice, and the flipped
version that printed clean. That model belongs to its designer and isn't mine to redistribute, so the
shipped test fixtures are synthetic parts built to reproduce the same geometry classes — and if you
happen to own the same model, pointing PRINTCHECK_FIXTURES at it runs the real regression
tests too.
It's MIT licensed, so do what you like with it. If it saves you a spool, that's the whole point.