Summary
SchemaExtractor only resolves types of the form pkg/msg/Type and always looks for <package share>/msg/<Type>.msg. Types published on action feedback topics (pkg/action/<Action>_FeedbackMessage) and on service introspection event topics (pkg/srv/<Srv>_Event, Jazzy+) have no such file, so get_schema() fails and the topic cannot be subscribed with a schema.
Reproduction (ROS 2 Jazzy)
Any action server, e.g. the tf2_msgs/action/LookupTransform action or a nav2 action, publishes /<action>/_action/feedback with type tf2_msgs/action/LookupTransform_FeedbackMessage (the generated type exists in tf2_msgs/action/detail/lookup_transform__struct.hpp).
SchemaExtractor::try_get_message_definition("tf2_msgs/action/LookupTransform_FeedbackMessage"):
parse_message_type() (ros2/src/schema_extractor.cpp, ~line 205) keeps only the first segment as package and the last as type name, discarding action.
build_message_definition_recursive() then reads <share>/tf2_msgs/msg/LookupTransform_FeedbackMessage.msg (ros2/src/schema_extractor.cpp:92), which does not exist. The result is "failed to resolve message definition".
The same happens for pkg/srv/Foo_Event when service introspection is enabled.
Expected
The feedback message is defined by the .action file: X_FeedbackMessage is unique_identifier_msgs/UUID goal_id plus X_Feedback feedback, where X_Feedback is the third section of action/X.action. Service events are defined by the .srv file plus service_msgs/msg/ServiceEventInfo. rosbag2 resolves both in rosbag2_cpp/src/rosbag2_cpp/message_definitions/local_message_definition_source.cpp (see the /action/ and _Event handling around lines 304-346), and it locates interface files through the package's rosidl_interfaces ament resource (ament_index_cpp::get_resource("rosidl_interfaces", pkg, ...)) rather than a fixed path.
Suggested fix
- Parse the middle segment (
msg, srv, action) instead of discarding it.
- Locate files through the
rosidl_interfaces resource index.
- For
action, synthesise X_FeedbackMessage (and X_Goal, X_Result if ever needed) from the .action sections; for srv _Event, synthesise from the .srv sections plus ServiceEventInfo.
A related limitation: types that only ship an .idl (no .msg) are also unresolvable; rosbag2 falls back to the .idl text with encoding ros2idl.
Found while porting SchemaExtractor into another recorder, after comparing it with rosbag2's implementation. Happy to open a PR if the approach above is acceptable.
Reported with the help of Claude Code.
Summary
SchemaExtractoronly resolves types of the formpkg/msg/Typeand always looks for<package share>/msg/<Type>.msg. Types published on action feedback topics (pkg/action/<Action>_FeedbackMessage) and on service introspection event topics (pkg/srv/<Srv>_Event, Jazzy+) have no such file, soget_schema()fails and the topic cannot be subscribed with a schema.Reproduction (ROS 2 Jazzy)
Any action server, e.g. the
tf2_msgs/action/LookupTransformaction or a nav2 action, publishes/<action>/_action/feedbackwith typetf2_msgs/action/LookupTransform_FeedbackMessage(the generated type exists intf2_msgs/action/detail/lookup_transform__struct.hpp).SchemaExtractor::try_get_message_definition("tf2_msgs/action/LookupTransform_FeedbackMessage"):parse_message_type()(ros2/src/schema_extractor.cpp, ~line 205) keeps only the first segment as package and the last as type name, discardingaction.build_message_definition_recursive()then reads<share>/tf2_msgs/msg/LookupTransform_FeedbackMessage.msg(ros2/src/schema_extractor.cpp:92), which does not exist. The result is "failed to resolve message definition".The same happens for
pkg/srv/Foo_Eventwhen service introspection is enabled.Expected
The feedback message is defined by the
.actionfile:X_FeedbackMessageisunique_identifier_msgs/UUID goal_idplusX_Feedback feedback, whereX_Feedbackis the third section ofaction/X.action. Service events are defined by the.srvfile plusservice_msgs/msg/ServiceEventInfo. rosbag2 resolves both inrosbag2_cpp/src/rosbag2_cpp/message_definitions/local_message_definition_source.cpp(see the/action/and_Eventhandling around lines 304-346), and it locates interface files through the package'srosidl_interfacesament resource (ament_index_cpp::get_resource("rosidl_interfaces", pkg, ...)) rather than a fixed path.Suggested fix
msg,srv,action) instead of discarding it.rosidl_interfacesresource index.action, synthesiseX_FeedbackMessage(andX_Goal,X_Resultif ever needed) from the.actionsections; forsrv_Event, synthesise from the.srvsections plusServiceEventInfo.A related limitation: types that only ship an
.idl(no.msg) are also unresolvable; rosbag2 falls back to the.idltext with encodingros2idl.Found while porting
SchemaExtractorinto another recorder, after comparing it with rosbag2's implementation. Happy to open a PR if the approach above is acceptable.Reported with the help of Claude Code.