Bug report
Steps to reproduce
- Run a gateway whose image does not contain a message package that is present in the ROS graph,
for example nav2_msgs.
GET /api/v1/apps/<id>/data/<url-encoded topic of that type>.
- Execute an operation backed by a service or action whose type comes from a package the gateway
image does not have.
- Separately, set up a case where the package resolves when the subscription is created, but its
introspection library is missing.
Expected behavior
"This type is not installed here" is a different answer from "the gateway failed". A client that
walks the endpoint tree can tell them apart, and the tree does not advertise a resource it can
never serve.
Actual behavior
Steps 2 and 3 return 500, the same on the owning gateway and through an aggregator:
{"error_code": "vendor-error",
"message": "package 'nav2_msgs' not found",
"parameters": {"entity_id": "<app-id>", "topic_name": "/<topic>"},
"vendor_code": "x-medkit-subscribe-failed"}
The gateway is working correctly here. The type is simply not installed. As a 500 it cannot be
told apart from a gateway fault by any client walking the endpoints.
Step 4 returns 200 OK with x-medkit.status = "metadata_only" and an empty type_info.
The metadata_only fallback itself is deliberate and useful. #52 added it so that a topic which
is not currently publishing returns its type, schema and default-value template instead of a 404.
The point of the fallback is that the client still gets the schema. This is the one case where
there is no schema to give, because the type cannot be introspected. The response then looks the
same as an idle topic and carries nothing the client can use. A consumer cannot tell "no
publisher right now" from "this gateway can never decode this type".
Environment
- ros2_medkit version: main (a268379), gateway vendor_info.version 0.6.0, SOVD API 1.0.0
- ROS 2 distro: Jazzy
- OS: Ubuntu 24.04
Additional information
The 500 comes from src/data/ros2_topic_data_provider.cpp:380-383, which wraps any failure to
create the subscription as ErrorInfo{ERR_X_MEDKIT_SUBSCRIBE_FAILED, ..., 500, ...}.
The exception type is already lost by then. Ros2SubscriptionExecutor::run_sync
(include/ros2_medkit_gateway/ros2_common/ros2_subscription_executor.hpp:344) catches
const std::exception & and stores ex.what() as a plain std::string. So
ament_index_cpp::PackageNotFoundError and a real rcl fault arrive at the handler as the same
thing. Telling them apart in the handler needs the type kept at that boundary.
The 200 path is src/data/ros2_topic_data_provider.cpp:502-517. TypeNotFoundError from the
serializer is caught, logged once per type, and sets result.has_data = false. The empty
type_info comes from src/ros2_medkit_serialization/src/type_introspection.cpp:73-86:
get_type_schema throws for a type that cannot be resolved, the schema falls back to an empty
object, and the result is deliberately not cached because resolution may be temporary. So the
same code that leaves the schema empty already knows the type could not be resolved.
Operations collapse the same way, to 500 with x-medkit-ros2-service-unavailable and
x-medkit-ros2-action-unavailable (src/http/handlers/operation_handlers.cpp:705-707,
:675-677).
Two things that already exist and are not used:
ERR_X_MEDKIT_ROS2_TYPE_INTROSPECTION_FAILED is declared at
include/ros2_medkit_gateway/core/http/error_codes.hpp:91 and has no other reference in the
tree.
415 does not appear anywhere in the repository. In the data path, 501 is used only for
data-categories and data-groups.
Capabilities and the per-topic list are not filtered by whether a type can be resolved. The app
and component capability vectors are hard-coded
(src/http/handlers/discovery_handlers.cpp:1112-1114, :741-744), and the per-topic list logs a
DEBUG line and lists the item anyway when introspection fails
(src/http/handlers/data_handlers.cpp:106-109). So /data advertises resources the gateway
cannot serve. That part overlaps #515.
Bug report
Steps to reproduce
for example
nav2_msgs.GET /api/v1/apps/<id>/data/<url-encoded topic of that type>.image does not have.
introspection library is missing.
Expected behavior
"This type is not installed here" is a different answer from "the gateway failed". A client that
walks the endpoint tree can tell them apart, and the tree does not advertise a resource it can
never serve.
Actual behavior
Steps 2 and 3 return
500, the same on the owning gateway and through an aggregator:{"error_code": "vendor-error", "message": "package 'nav2_msgs' not found", "parameters": {"entity_id": "<app-id>", "topic_name": "/<topic>"}, "vendor_code": "x-medkit-subscribe-failed"}The gateway is working correctly here. The type is simply not installed. As a 500 it cannot be
told apart from a gateway fault by any client walking the endpoints.
Step 4 returns
200 OKwithx-medkit.status = "metadata_only"and an emptytype_info.The
metadata_onlyfallback itself is deliberate and useful. #52 added it so that a topic whichis not currently publishing returns its type, schema and default-value template instead of a 404.
The point of the fallback is that the client still gets the schema. This is the one case where
there is no schema to give, because the type cannot be introspected. The response then looks the
same as an idle topic and carries nothing the client can use. A consumer cannot tell "no
publisher right now" from "this gateway can never decode this type".
Environment
Additional information
The 500 comes from
src/data/ros2_topic_data_provider.cpp:380-383, which wraps any failure tocreate the subscription as
ErrorInfo{ERR_X_MEDKIT_SUBSCRIBE_FAILED, ..., 500, ...}.The exception type is already lost by then.
Ros2SubscriptionExecutor::run_sync(
include/ros2_medkit_gateway/ros2_common/ros2_subscription_executor.hpp:344) catchesconst std::exception &and storesex.what()as a plainstd::string. Soament_index_cpp::PackageNotFoundErrorand a real rcl fault arrive at the handler as the samething. Telling them apart in the handler needs the type kept at that boundary.
The 200 path is
src/data/ros2_topic_data_provider.cpp:502-517.TypeNotFoundErrorfrom theserializer is caught, logged once per type, and sets
result.has_data = false. The emptytype_infocomes fromsrc/ros2_medkit_serialization/src/type_introspection.cpp:73-86:get_type_schemathrows for a type that cannot be resolved, the schema falls back to an emptyobject, and the result is deliberately not cached because resolution may be temporary. So the
same code that leaves the schema empty already knows the type could not be resolved.
Operations collapse the same way, to
500withx-medkit-ros2-service-unavailableandx-medkit-ros2-action-unavailable(src/http/handlers/operation_handlers.cpp:705-707,:675-677).Two things that already exist and are not used:
ERR_X_MEDKIT_ROS2_TYPE_INTROSPECTION_FAILEDis declared atinclude/ros2_medkit_gateway/core/http/error_codes.hpp:91and has no other reference in thetree.
415does not appear anywhere in the repository. In the data path,501is used only fordata-categoriesanddata-groups.Capabilities and the per-topic list are not filtered by whether a type can be resolved. The app
and component capability vectors are hard-coded
(
src/http/handlers/discovery_handlers.cpp:1112-1114,:741-744), and the per-topic list logs aDEBUG line and lists the item anyway when introspection fails
(
src/http/handlers/data_handlers.cpp:106-109). So/dataadvertises resources the gatewaycannot serve. That part overlaps #515.