How to generate an update artifact for Debian OS - what is the recommended flow?

I’m struggling with this for some days and decided to write a forum post even though it seems like a simple use-case.

I see these options:

  1. mender-convert way: use mender-convert as if creating a first-time system .img, discard the generated .img and use the generated .mender file for OTA update. I can’t get this to work because of size mismatches (more on that later)
  2. mender-artifact way: clone the root filesystem and use it as an input for mender-artifact. I have no idea how is it different from 1.
  3. system snapshot way: which is as I understand basically a mender-artifact way with some ssh sprinkles on it

Now, the situation that I’m in:
I successfully created my initial .img and .mender files via mender-convert following the docs. I flashed it and (with some adventures along the way) now I have a seemingly working Mender-ready machine with boot, rootfsA, rootfsB and data partitions. I am able to successfully “update” the system with the original .mender artifact e.g. if I change some files, wallpaper etc. I can then deploy an update and the machine will wake up on another rootfs with previos state, mender ui shows green checkmark etc.

However, I’ve changed a bunch of things on my system and now I want to create a new .mender artifact from it - this is where I fail.

First I tried option 1., because it has the word “recommended” attached to it, following the exact steps I made originally. However, the update failed with

Update (32405192704 bytes) is larger than the size of device /dev/sda3 (31356616704 bytes)

I tried to fiddle with MENDER_STORAGE_TOTAL_SIZE_MB, IMAGE_OVERHEAD_FACTOR and IMAGE_ROOTFS_SIZE but to no avail.
On my original mender-convert run (the one that generated the .img present on the device and a working artifact) I set MENDER_STORAGE_TOTAL_SIZE_MB="60000 and IMAGE_ROOTFS_SIZE=-1. When running these options now, mender-convert complains that 60000 MB is too small.

On my most recent run I set: MENDER_STORAGE_TOTAL_SIZE_MB="62000", IMAGE_OVERHEAD_FACTOR="0" and IMAGE_ROOTFS_SIZE="31356616". I took this number directly from the error message pasted above and rounded down to KB.
When running mender-artifact read on the resulting artifact I get

Updates:
  - Type: rootfs-image
    ...
    Depends: {}
    Clears Provides: [artifact_group, rootfs_image_checksum, rootfs-image.*]
    Metadata: {}
    Files:
      - checksum: ...
        modified: 2025-06-09 15:53:39 +0200 CEST
        name: rootfs.img
        size: 32109174784

Can someone explain why, even when explicitly setting IMAGE_ROOTFS_SIZE="31356616" I got a larger rootfs in the payload?

From the docs (granted this entry is from Yocto docs):

IMAGE_ROOTFS_SIZE
The size of the generated rootfs, expressed in kiB. This will be the size of the rootfs image shipped in a .mender update.

Also from the docs (this time Debian docs):

IMAGE_OVERHEAD_FACTOR
This factor is multiplied by the used space value for the generated rootfs, and if the result is larger than IMAGE_ROOTFS_SIZE + IMAGE_ROOTFS_EXTRA_SPACE, it will be used as the size of the rootfs instead of the other two variables

Used space on my rootfs was around 22gb. Yet it looks like it ignored my IMAGE_ROOTFS_SIZE anyway, even with IMAGE_OVERHEAD_FACTOR=0

I can provide more detail if anyone’s willing to help.
Thank you.

My preferred way of generating update artifacts for Debian is to generate the images from scratch:

  1. Bootstrap a minimal Debian root file system using e.g. debootstrap or mmdebstrap.
  2. Customize the root file system according to the project needs.
  3. Based on the tailor made root file system from step 2 generate artifacts such as: (1) Full OS images that can be flashed to the target system (genimage is a good helper tool). (2) Mender update artifacts (mender-artifact helps to create those artifacts). (3) SBOMs (syft can help here). (4) Any other artifact that is helpful for your project.

The benefits of this approach are:

  1. You get reproducible artifacts.
  2. No target hardware is required to generate the artifacts.
  3. With appropriate tooling, you can create all artifacts with one single command.

To orchestrate the above steps, I have created a tool called edi. You can try it out e.g. using a Raspberry Pi. There are other tools like debos, rugix, elbe and isar that serve a similar purpose.