← Back to Wiki
3D Printing / Tools

printcheck — Catch the Print That Will Fail Before You Spend the Filament

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.

Share on X

Download

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.

The two numbers your slicer won't show you

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.

1. Height divided by the smallest footprint dimension

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.

2. Flat down-facing area sitting above the plate

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.

Diffing gcode against a print you know worked

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:

The silent one: unresolved inherits

This 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.

What it doesn't do

Scope and testing

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.