Bed Z offset compared to machine 0 with bed mesh leveling

I have an issue with bed mesh leveling. Does the bed’s median 0 height has to match the machine 0?
For a specific print setup my whole bed is shifted up by 6mm compared to machine 0 (at all measurement points), ran a bed mesh calibration from mainsail and I got a really strange result. The first layer went down fine, but then during the mesh fade this 6mm offset got faded out, resulting in the first 10mm of the model squished into 4mm (I have fade end at 10mm). I was expecting the model to be shifted up by the bed’s average z height (6mm), then only the variances being compensated for with the fading.
Is this normal, or do I have to enable some additional settings besides the defaults listed on the help pages? Or is the average offset not compensated for?

This is how the mesh looks like:

And here are the probed heights:

6.202500, 6.232500, 6.062500, 5.832500
6.147500, 6.172500, 6.122500, 5.947500
6.032500, 6.122500, 6.162500, 6.092500
5.935000, 6.140000, 6.140000, 6.132500

You need to use a relative reference index when using a separate probe and z endstop. That will make the reference point you choose (typically the middle of the bed) relative to Z0 and move the entire mesh down to the correct height.

Yes I’m using Z endstops. Two actually, because this is a machine with two Z steppers.
As I understand that option is not what it’s for. It just offsets the whole bed mesh by the given relative point. Running a bed mesh calibrate with the relative reference set to 0 resulted in only the variance being stored in the mesh compared to the selected reference point. The 6mm offset “disappeared”. The result is that the head tries to move into the bed. If I were using the probe as the endstop relative ref index would work, but then gantry leveling becomes an issue.
Regardless I tried it out and it resulted in the head crashing into the bed (if I would not have removed previously as a precaution).

What I’m looking for from the behavior point of view: lets say that the given probed point is 6.5mm, and the average of all probed points is 6mm. When I issue a G1Z0 command I expect the machine to move to 6.5mm absolute. When I issue a G1Z10 command I expect the machine to move to 16.0mm (command + average offset + variance faded out).
What is currently happening without relative ref index is G1Z0 → 6.5mm; G1Z10 → 10mm.
With relative ref index (and 6mm picked as the reference) → G1Z0 is 0.5mm (crash into the bed wrong!), G1Z10 → 10mm (wrong).

Not sure I understand what you want, but Klipper is designed to work only one way when using a separate probe and offset.

You need to calibrate your endstops using z_endstop_calibrate. You should leave your probe z offset at zero and use a relative reference index point. That is an index of probed points, so you should use the middle point. The index starts at 0, so the middle point of a 3x3 mesh would be 4, or the middle of a 5x5 would be 12.

With Klipper properly configured and a mesh loaded, Klipper will maintain the distance between the nozzle and the bed using a gcode offset that matches the mesh. So regardless of how high or low any point on the bed is relative to the endstop, the nozzle will maintain its height above the bed.

What I want is to not squish the first 10mm of the printed part into 4mm because the bed is 6mm higher than the machine 0. I don’t wan’t to edit the config file each time I have a different average bed height.

I set the probe z offset to 0 (deleted it from the config) then I ran z_endshop_calibrate. This then adds the z offset back, exactly the same value as before, so I’m back to square one.

This is not true (in all cases, see later), if I have fading enabled to get accurate feature sizes once the fading region ends.

And I found the issue. I had “fade_target” set to 0, as per the default in the documentation:
Doing so overrides the actual default value which is the average bed offset what I was looking for…
Solution is, not set fade_target to any value, leave it out of the configuration completely.
Now when I issue a G1Z100, the machine moves to the expected Z106 (100 + average bed height).
I think the documentation on this part could be refined to include this fade_target, but commented out.
I wonder how many people got this wrong too. Because this remains hidden until the machine zero and the bed average zero significantly differs.

IMO the documentation is pretty clear and clearly mentions “Default Value: The average Z value of the mesh” :

fade_target: 0
Default Value: The average Z value of the mesh

Generally its a good idea to leave fade_target out of the configuration so the average height of the mesh is used, however it may be desirable to manually adjust the fade target if one wants to print on a specific portion of the bed.

No its not. Neither the textual description, or the example is clear. For all other values the listed default/example value equals to the actual default value/behavior. Here the shown “fade_target: 0” is not the default value. Here the existence of the parameter regardless of its value carries additional information.
For all other configuration parameter/block one can just take the example values from the documentation because that does not override the defaults.
What would make it better is, either include this parameter commented out at the start of that paragraph, or have a special value (string) for “average bed height” then that used as the example value.

The mesh fade documentation differs from the configuration reference, the configuration reference shows mandatory parameters as not commented out ones, and optional ones commented out with their default value. I might give this a pass in all other cases, but when the existence of a parameter carries additional not described behavior its not at all clear.

Source: Configuration reference - Klipper documentation

Source: Bed Mesh - Klipper documentation

I can’t see any issue.

I can see two issues:
Bed Mesh - Klipper documentation

(A) This is supposed to be an example configuration. The fade_target should not be specified here, or at least commented out. Many users (including me) use these examples as the starting point and only changes the parameters which they need to, assuming that the rest is a good starting point.
(B) the value 0 and the default value is not the same. 0 is not the default value. Nor there is any default value that matches the default behavior. Two parameters are hidden behind one, the behavior of the fade_target and if the behavior is set to “target a value” then its the target value.

I would comment out (A), and change (B) from “Default Value:” to “If left unspecified:” or similar.

The configuration reference could also be improved, the text you highlighted (“Default is the …”) changed to “If left unspecified the average z value of the currently loaded mesh is used.”

Sentence fragment or grammar issue. … will have an accurately sized… what?

From the Mesh Fade documentation

By setting the fade_target to .2, the homed area will expand by .2 mm, however the rest of the bed will have an accurately sized.

Suggested rewrite:
The fade_target can be thought of as an additional Z offset applied to the entire bed after fade completes. Generally speaking we would like this value to be 0, however there are circumstances where it should not be. For example, let’s assume the homing position on the bed is an outlier that is .2 mm lower than the average probed height of the bed. If the fade_target is 0, fade will shrink the print vertically by an average of .2 mm across the bed. To counteract that, setting the fade_target to .2 will expand the area above the mesh vertically by .2 mm. However, the rest of the bed will have an accurately sized [igloo in the arctic!?!?!?]. Generally it is good to leave fade_target out of the configuration so that the average height of the mesh is used. However, it may be desirable to manually adjust the fade target if one wants to print on a specific portion of the bed that is known to deviate from the mesh average.