Summary
diagnostic_updater 4.2.7 changed the signature of the exported Updater constructor within the Jazzy distribution, released as a patch bump over 4.2.6. Any downstream shared object compiled against 4.2.6 fails at load time with undefined symbol after a routine apt upgrade pulls in ros-jazzy-diagnostic-updater 4.2.7. Because the change shipped as a patch release with no changelog entry, there was no signal to downstream packagers that a rebuild was required.
The change
#354 ("Add starting_up_state parameter to Updater") appends a trailing defaulted parameter to both Updater constructors and adds a new private member:
Updater(
std::shared_ptr<rclcpp::node_interfaces::NodeBaseInterface> base_interface,
/* ... five more interface params ... */
double period = 1.0,
unsigned char starting_up_status = diagnostic_msgs::msg::DiagnosticStatus::OK); // new
...
private:
...
unsigned char starting_up_status_; // new
It was auto-backported to ros2-jazzy by mergify as #584 (merged 2026-05-20) and released in 4.2.7 (2026-05-26). The same backport went to humble (#583) and kilted (#585), so those distro branches carry the same latent break.
The PR was assessed as non-breaking because the defaulted argument preserves source compatibility, but it is not binary compatible:
- The exported constructor symbol changed. The non-template
Updater constructor is defined in diagnostic_updater.cpp and exported from libdiagnostic_updater.so. The trailing parameter changes the mangled name (the parameter list suffix moves from ...Ed to ...Edh), and no overload with the old signature was retained. Callers linked against 4.2.6 request a symbol 4.2.7 no longer exports.
sizeof(Updater) changed. The new starting_up_status_ member grows the object, so any downstream code that embeds or derives from Updater has a stale layout even where linking succeeds.
Observable with:
$ nm -DC /opt/ros/jazzy/lib/libdiagnostic_updater.so | grep 'Updater::Updater'
# 4.2.6-1noble: ..., double)
# 4.2.7-1noble: ..., double, unsigned char)
Impact
We ship deployed robots (Ubuntu 24.04 / Jazzy) running composed containers whose components hold a diagnostic_updater::Updater. A routine apt upgrade moved ros-jazzy-diagnostic-updater from 4.2.6-1noble (built 2026-01) to 4.2.7-1noble (built 2026-06). Components built against 4.2.6 then fail at load with undefined symbol for the old constructor, which kills the composed container and takes unrelated components down with it.
There is also no clean rollback story: once some packages in an ecosystem are rebuilt against 4.2.7 and others remain on 4.2.6, no single installed version of diagnostic_updater satisfies both, and packages.ros.org only retains the newest build, so pinning back to 4.2.6 is fragile.
The 4.2.7 changelog for diagnostic_updater does not mention #354/#584 at all, so even a careful downstream reading the release notes would not have caught this.
Expected behaviour
Within a released, stable distribution, a patch-level bump of a binary-distributed C++ library should be ABI compatible — or the release should be versioned and documented so downstream consumers know a rebuild is required.
Summary
diagnostic_updater4.2.7 changed the signature of the exportedUpdaterconstructor within the Jazzy distribution, released as a patch bump over 4.2.6. Any downstream shared object compiled against 4.2.6 fails at load time withundefined symbolafter a routineapt upgradepulls inros-jazzy-diagnostic-updater4.2.7. Because the change shipped as a patch release with no changelog entry, there was no signal to downstream packagers that a rebuild was required.The change
#354 ("Add starting_up_state parameter to Updater") appends a trailing defaulted parameter to both
Updaterconstructors and adds a new private member:It was auto-backported to
ros2-jazzyby mergify as #584 (merged 2026-05-20) and released in 4.2.7 (2026-05-26). The same backport went to humble (#583) and kilted (#585), so those distro branches carry the same latent break.The PR was assessed as non-breaking because the defaulted argument preserves source compatibility, but it is not binary compatible:
Updaterconstructor is defined indiagnostic_updater.cppand exported fromlibdiagnostic_updater.so. The trailing parameter changes the mangled name (the parameter list suffix moves from...Edto...Edh), and no overload with the old signature was retained. Callers linked against 4.2.6 request a symbol 4.2.7 no longer exports.sizeof(Updater)changed. The newstarting_up_status_member grows the object, so any downstream code that embeds or derives fromUpdaterhas a stale layout even where linking succeeds.Observable with:
Impact
We ship deployed robots (Ubuntu 24.04 / Jazzy) running composed containers whose components hold a
diagnostic_updater::Updater. A routineapt upgrademovedros-jazzy-diagnostic-updaterfrom4.2.6-1noble(built 2026-01) to4.2.7-1noble(built 2026-06). Components built against 4.2.6 then fail at load withundefined symbolfor the old constructor, which kills the composed container and takes unrelated components down with it.There is also no clean rollback story: once some packages in an ecosystem are rebuilt against 4.2.7 and others remain on 4.2.6, no single installed version of
diagnostic_updatersatisfies both, and packages.ros.org only retains the newest build, so pinning back to 4.2.6 is fragile.The 4.2.7 changelog for
diagnostic_updaterdoes not mention #354/#584 at all, so even a careful downstream reading the release notes would not have caught this.Expected behaviour
Within a released, stable distribution, a patch-level bump of a binary-distributed C++ library should be ABI compatible — or the release should be versioned and documented so downstream consumers know a rebuild is required.