Check duplicate issues.
Description
When an I/O customization rule has more than one source member, RNTuple applies it incorrectly: every target member receives the value of the first source member of its type, and that value isn't exact for floating point (1.5 read back as 1.5000000000000002). A rule with a single source member works as expected. The same dictionary reads the equivalent TTree data correctly, and the generated dictionary wrapper seems to have correct per-member offset_Onfile_* entries, so the onfile staging offsets appear to collapse per member type on the RNTuple side.
I wouldn't exclude user error, I found it quite hard to find documentation on the I/O customization rules.
Real-world occurrence: ShipSoft/data-model#25
(6 structs, ~30 renamed members; TTree reads correctly, RNTuple collapses).
Reproducer
(Full reproduction script: reproduce.sh bash reproduce.sh (self-contained, builds old/new dictionaries and computes the checksum at run time))
Renaming members of a plain unversioned struct:
// on disk: struct Hit { int a; int b; double x; double y; }; a=1 b=2 x=1.5 y=2.5
#pragma read sourceClass="Hit" targetClass="Hit" checksum="[<old>]" \
source="int a; int b; double x; double y" target="a_r,b_r,x_r,y_r" \
code="{ a_r = onfile.a; b_r = onfile.b; x_r = onfile.x; y_r = onfile.y; }"
Expected behaviour
Each onfile.<member> refers to that member's staged on-disk value, as in the TTree case.
Actual behaviour
First value of a given type is reused for all following (and for floating point numbers does not seem to be exact):
a_r want 1 got 1 ok
b_r want 2 got 1 WRONG
x_r want 1.5 got 1.5000000000000002 WRONG
y_r want 2.5 got 1.5000000000000002 WRONG
ROOT version
------------------------------------------------------------------
| Welcome to ROOT 6.40.02 https://root.cern |
| (c) 1995-2025, The ROOT Team; conception: R. Brun, F. Rademakers |
| Built for linuxx8664gcc on Jul 13 2026, 09:13:28 |
| From tags/6-40-02@6-40-02 |
| With std202302 |
| Try '.help'/'.?', '.demo', '.license', '.credits', '.quit'/'.q' |
------------------------------------------------------------------
Installation method
conda-forge, root_base 6.40.02 cxx23_hbf4e8c7_2, linux-64
Operating system
Linux (NixOS)
Additional context
Maybe related to #17713 ("fix I/O rule handling for unversioned classes"). Maybe also related to a TTree unversioned-class lookup problem: #14491.
Check duplicate issues.
Description
When an I/O customization rule has more than one source member, RNTuple applies it incorrectly: every target member receives the value of the first source member of its type, and that value isn't exact for floating point (
1.5read back as1.5000000000000002). A rule with a single source member works as expected. The same dictionary reads the equivalent TTree data correctly, and the generated dictionary wrapper seems to have correct per-memberoffset_Onfile_*entries, so the onfile staging offsets appear to collapse per member type on the RNTuple side.I wouldn't exclude user error, I found it quite hard to find documentation on the I/O customization rules.
Real-world occurrence: ShipSoft/data-model#25
(6 structs, ~30 renamed members; TTree reads correctly, RNTuple collapses).
Reproducer
(Full reproduction script: reproduce.sh
bash reproduce.sh(self-contained, builds old/new dictionaries and computes the checksum at run time))Renaming members of a plain unversioned struct:
Expected behaviour
Each
onfile.<member>refers to that member's staged on-disk value, as in the TTree case.Actual behaviour
First value of a given type is reused for all following (and for floating point numbers does not seem to be exact):
ROOT version
Installation method
conda-forge,
root_base 6.40.02 cxx23_hbf4e8c7_2, linux-64Operating system
Linux (NixOS)
Additional context
Maybe related to #17713 ("fix I/O rule handling for unversioned classes"). Maybe also related to a TTree unversioned-class lookup problem: #14491.