A printer flashed back to stock came up with the FlashForge screen and no Klipper behind it, and stayed that way however many times the stock package was flashed. The .cfg files were the obvious suspect and are not the fault: stock's run.sh does `cp $WORK_DIR/klipper/config/* /usr/data/config/ -rf`, and the printer's busybox unlinks a dangling symlink rather than writing through it, so printer.base.cfg and the seven beside it come back on every stock flash. The ff-*.cfg links left behind resolve to nothing and are included by nothing. Even the SAVE_CONFIG block our Klipper wrote into printer.cfg is harmless -- configfile.py marks every autosave section valid through access_tracking, so `[ff_tool 0]` there is not a config error on a stock klippy. All three were put to the printer's own binaries in the replica. What survives is /usr/prog/klipper/klipperDaemon. Every release links it at the mod, whose `start` does nothing on purpose -- klippy is an s6-rc longrun and a second unsupervised one would fight it for /dev/ttyS4 -- and the stock package has no klipperDaemon to copy over it: not in the software component, not in its md5sum.list, no line in run.sh. Stock's start.sh ends in `klipperDaemon start`, so the UI starts and klippy never does. installer/recovery.sh is the repair, packed by bin/pack-recovery.sh into a .tgz that carries no mod at all: FlashForge's own klipperDaemon, taken off a factory /usr/prog and gated on its md5, and their Klipper configs out of the stock package the build reads. It sweeps FlashForge's config directory by shape rather than by a list of names -- a symlink into $MODDIR there can only be ours -- refuses to run while the mod is still the firmware, and never touches printer.cfg, which no package has a copy of to put back. Output goes to work/recovery/: bin/pack.sh wipes work/out, and the replica lane installs the newest .tgz there as the mod under test. qa/replica/test_recovery.py holds the whole story against a real machine: the link the mod leaves, the busybox cp, the refusal, `klipperDaemon start` leaving no pid file, then the same command forking a real klippy once the file is back. Publishing lives in Klipper4FlashForge/stock-recovery, which checks this repo out and releases there, so a repair for owners of old releases is not buried among firmware releases they must not flash to get it. Two things found on the way, both in the harness rather than the mod: seed-prog.sh appended USER-CONFIG-MUST-SURVIVE as a plain comment after the SAVE_CONFIG header, and Klipper drops the entire autosave block on the first line there that does not start with '#*#'. Every replica ran with klippy seeing none of the machine's saved PID, shaper, mesh or probe values, and failing on an unrelated-looking missing option. It is written inside the block now, an older image's copy is repaired in place, and test_install.py asserts the invariant. installed_image() keyed its cache on the package md5 alone, so a rebuilt PRINTER_IMAGE silently handed back a bake from the old base -- which made the fix above read as ineffective twice before the cache was the suspect. The tag mixes in the base image id now, and build-printer-image.sh takes IMAGE_TAG so a rebuilt image can be published without moving a tag ci.yml pins. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015hdzEqXuFcY4xXALGPbBFV
4.7 KiB
Installing
The printer's own updater does the work: one file on a FAT32 stick, plugged in at power-on. No jailbreak, no soldering, no opening the case, no ssh.
What to have ready
Before you flash anything:
- The stock FlashForge package for your model, downloaded and to hand. It is the undo button: copy it to a stick and flash it, and the printer is back to how it was. That is the only recovery step needing nothing but a USB port — no ssh, no screen. The stock packages are published at ghzserg/FF.
- Your printer's model, from Settings → About. A package for the other model is refused, and it is not a valid recovery image either.
- The printer's IP address, and a machine that can reach it.
- Time to stand at the machine. The first print after a flash is not something to start and walk away from.
Whatever stick you use: FAT32, with the package at the root of it, not in a folder.
Which file do I need
Creator 5 and Creator 5 Pro are not interchangeable. The printer refuses a package built for the other model — the most common reason a flash "does nothing" — so pick the file whose name matches your machine on the Releases page:
| Your printer | The file |
|---|---|
| Creator 5 | Creator5-anvil-<date>.tgz |
| Creator 5 Pro | Creator5Pro-anvil-<date>.tgz |
Not sure which you have? On the printer: Settings → About.
The flash
- Format a USB stick as FAT32. Not exFAT, not NTFS.
- Copy the file for your model to the root of the stick. Not in a folder. Leave the name exactly as it is — the printer looks for that pattern.
- Power the printer off.
- Plug the stick in and power the printer on. It finds the package by itself and starts installing. The screen tells you to wait while it works; this takes a few minutes. Do not cut the power.
- Wait for the beep. The printer sounds when the install has finished.
- Reboot manually. Turn the power switch on the right side of the printer, near the power cable, off and on again.
- Pull the stick once it has rebooted — your root password is on it, in
anvil-password.txt.
The boot after that one is the long one, and it is the mod's rather than FlashForge's: a progress bar on a plain screen, for a minute or two, before HelixScreen appears. What the first boot does says what is happening behind it.
What the first boot does
The first boot after a flash is longer than the ones after it, and the screen shows a progress bar rather than HelixScreen for most of it. What you'll see, partway through and at the end:
Two things happen that happen only once:
- Your machine's factory calibration comes across. The dock and nozzle positions measured for your printer at the factory are copied into Klipper's own configuration, so it starts from its own numbers rather than from nothing. You do not have to do anything for this.
- A root password is chosen, and written to the stick. See below.
Do not cut the power during the first boot. While that copy is being saved is the one moment where an interrupted boot can cost you the factory numbers.
Your root password
The first install picks a random root password for your printer and writes it
to anvil-password.txt on the stick you flashed from. Read it, save it
somewhere safe, and delete the file from the stick.
- If the stick is not writable, no password is set at all — the install log says so.
- Later updates keep whatever password the printer already has, including one you have changed yourself. The stick gets a password exactly once.
Check that ssh root@<printer-ip> works before you go any further. That shell
is how you get in when the screen is dark, and it is worth confirming while
everything is still fine.
What it changes on the printer
Nothing you have to configure. The package brings its own Klipper additions and config files with it and wires them up itself, so the printer comes up working.
Your printer.cfg is never touched — not by this flash and not by any
update. It is your file, it is where your own settings go, and leaving it
alone is also part of why flashing back to
stock works cleanly.
Then work through Your first print, in order, with the emergency stop within reach: it starts with the checks that say whether the flash went well.

