Troubleshooting & FAQ

Common issues and solutions when using ros2_medkit.

Installation Issues

rosdep fails to find packages

ERROR: the following packages/stacks could not have their rosdep keys resolved

Solution: Initialize and update rosdep:

sudo rosdep init  # Only needed once
rosdep update

Cannot find ros2_medkit packages

Package 'ros2_medkit_gateway' not found

Solution: Source the workspace:

source ~/ros2_medkit_ws/install/setup.bash

Gateway Issues

Gateway shows no areas or components

Possible causes:

  1. No other ROS 2 nodes running - Start some nodes first

  2. Different ROS_DOMAIN_ID - Ensure all nodes use the same domain

  3. Discovery not complete - Wait a few seconds and refresh

The gateway logs a one-time Discovery summary a few seconds after startup with the peer node / topic / entity counts. When it sees no application nodes it also logs a warning that echoes the active ROS_DOMAIN_ID, RMW_IMPLEMENTATION and ROS_LOCALHOST_ONLY - check the gateway’s console or logs first, as it names the most likely cause.

Check with:

ros2 node list
ros2 topic list

“Connection refused” when accessing API

Possible causes:

  1. Gateway not running - Check process is active

  2. Wrong port - Default is 8080 (HTTP) or 8443 (HTTPS)

  3. Localhost binding - Gateway binds to 127.0.0.1 by default

For network access, set host to 0.0.0.0:

ros2 launch ros2_medkit_gateway gateway.launch.py server_host:=0.0.0.0

Topic data returns empty or timeout

Possible causes:

  1. Topic has no publishers - Check with ros2 topic info

  2. Publisher is slow - Increase timeout in config

  3. Topic type not supported - Check for custom message types

For idle topics, the gateway returns metadata instantly. If a topic has publishers but no data, check if messages are actually being published:

ros2 topic hz /your/topic

CORS errors in browser

Access to fetch blocked by CORS policy

Solution: Configure CORS in gateway params:

cors:
  allowed_origins: ["http://localhost:5173"]
  allowed_methods: ["GET", "PUT", "POST", "DELETE", "OPTIONS"]

Authentication Issues

“Invalid token” error

Possible causes:

  1. Token expired - Get a new token or use refresh token

  2. Wrong secret - Ensure JWT secret matches

  3. Malformed header - Format must be Authorization: Bearer <token>

“Insufficient permissions” error

Check your role has the required permission:

  • viewer - Read only

  • operator - Read + operations + data publish

  • configurator - Operator + configurations

  • admin - Full access

Token refresh fails

Refresh tokens are single-use. After refreshing, use the new refresh token from the response.

TLS/HTTPS Issues

“SSL certificate problem”

For development with self-signed certificates:

curl -k https://localhost:8443/api/v1/health

For production, use certificates from a trusted CA.

“Key does not match certificate”

Regenerate both certificate and key together:

./scripts/generate_dev_certs.sh ./certs

Docker Issues

Container can’t discover ROS 2 nodes

Ensure all containers use the same:

  1. Docker network

  2. ROS_DOMAIN_ID

  3. DDS configuration

For development, try network_mode: host.

Web UI can’t connect to gateway in container

  1. Gateway must listen on 0.0.0.0, not 127.0.0.1

  2. CORS must allow the UI origin

  3. Port must be exposed in docker-compose

Fault Manager Issues

Faults API returns 503 or empty

The Faults API requires ros2_medkit_fault_manager node:

ros2 run ros2_medkit_fault_manager fault_manager_node

Faults not appearing for my component

Components must use ros2_medkit_fault_reporter to report faults. The REST API is read-only for fault status.

Graph Provider Issues

Every edge shows “pending” / no metrics

The x-medkit-graph metrics model has exactly one source of live data: a /diagnostics producer whose DiagnosticStatus.name matches the topic’s fully-qualified name byte-for-byte. With no such producer running, every edge’s metrics_status stays "pending" forever - it never transitions to "active" or "error" on its own.

Possible causes:

  1. No ``/diagnostics`` producer is running - nothing publishes DiagnosticStatus messages for the topic at all.

  2. The producer’s monitored-topic list omits this topic - many producers (including the reference greenwave_monitor) resolve their monitored topics once at startup and never re-resolve; a topic added or renamed afterward is silently skipped forever.

  3. Name mismatch - DiagnosticStatus.name must equal the ROS topic name exactly (leading /, no aliasing, no shortened form). Any other string never matches, however close.

  4. Producer started before its publishers existed - a producer that resolves its monitored topics once at startup (see cause 2) must be started strictly after the topics it monitors already have live publishers in the ROS graph.

Check what is actually being published:

ros2 topic echo /diagnostics --once

If nothing appears, no producer is running - start one (see Graph Provider Plugin for the reference greenwave_monitor invocation). If a DiagnosticStatus for the topic IS present but the edge still reads pending, compare its name field character-for-character against the topic’s fully-qualified ROS name.

See Graph Provider Plugin for the full producer contract, and Graph Provider Configuration for the freshness/degradation thresholds that govern the active / error states once data does arrive.

Performance Issues

Slow response for component data

Possible causes:

  1. Many topics - Response time scales with topic count

  2. Slow publishers - 3-second timeout per topic by default

  3. Low parallelism - Increase max_parallel_topic_samples

Optimize with:

max_parallel_topic_samples: 20  # Increase from default 10
topic_sample_timeout_sec: 0.5   # Decrease from default 1.0

High CPU usage

Discovery is graph-event driven (polled every 100 ms), so a stable graph already incurs near-zero refresh overhead. On a graph with frequent node churn that does not need to be reflected immediately, raise the safety-backstop interval above the default 30000 to reduce the worst-case forced refresh rate:

refresh_interval_ms: 60000  # Raise from default 30s if recovery from a
                             # missed graph event can tolerate longer delay.

FAQ

Q: Does ros2_medkit modify my ROS 2 nodes?

No. ros2_medkit is read-only by default. It discovers existing nodes and exposes them via REST API. Write operations (publishing, service calls, parameter changes) only happen when explicitly requested via the API.

Q: Can I use ros2_medkit with ROS 1?

No. ros2_medkit requires ROS 2 (Jazzy, Humble, or Lyrical). For ROS 1 systems, consider using the ros1_bridge and running ros2_medkit on the ROS 2 side.

Q: Is ros2_medkit production-ready?

ros2_medkit is currently suitable for development and testing. For production:

  • Enable TLS encryption

  • Configure JWT authentication

  • Test thoroughly with your specific use case

  • Monitor performance under expected load

Q: How does ros2_medkit compare to rosbridge?

Feature

ros2_medkit

rosbridge

Protocol

REST/HTTP

WebSocket/JSON

Discovery

Automatic entity hierarchy

Topic/service access

Authentication

JWT with RBAC

None built-in

Fault management

Yes

No

SOVD compatible

Yes

No

Q: Can I extend ros2_medkit with custom endpoints?

Yes. The gateway plugin framework allows you to add custom REST endpoints via GatewayPlugin::get_routes(). Create a shared library (.so) that implements the GatewayPlugin base class and configure it in gateway_params.yaml. See Server Configuration for plugin configuration details.

Q: How do I report a bug or request a feature?

Getting Help

If your issue isn’t covered here:

  1. Search existing issues: https://github.com/selfpatch/ros2_medkit/issues

  2. Ask on Discord: https://discord.gg/6CXPMApAyq

  3. Open a new issue with: - ros2_medkit version - ROS 2 distribution - Steps to reproduce - Expected vs actual behavior - Relevant logs