Skip to content

ros_launch has no first-class support for Bazel-built nodes #417

Description

@frneer

#344 describes this as a known gap. This issue provides a concrete MRE and documents the full set of obstacles.

The natural ROS 2 pattern for launching a node:

launch_ros.actions.Node(package="my_pkg", executable="my_node")

does not work for Bazel-built nodes. They are never installed into an ament prefix, so ROS 2's libexec lookup (<prefix>/lib/my_pkg/my_node) always fails.

What doesn't work

import launch_ros.actions
from launch import LaunchDescription


def generate_launch_description():

    # This is how you'd naturally write it -- but it fails under Bazel because
    # `eg_talker` and `eg_listener` are not installed in any ament prefix.
    return LaunchDescription(
        [
            launch_ros.actions.Node(
                package="ros2_example_apps",
                executable="eg_talker",
            ),
            launch_ros.actions.Node(
                package="ros2_example_apps",
                executable="eg_listener",
            ),
        ]
    )
ros_launch(
    name = "roslaunch_eg_node_problem",
    data = [
        ":eg_listener",
        ":eg_talker",
    ],
    launch_file = "eg_launch_node_problem.py",
    workspace_name = ros2_example_bazel_installed,
)

A workaround

import launch_ros.actions
from launch import LaunchDescription
from python.runfiles import runfiles


def generate_launch_description():
    r = runfiles.Create()
    prefix = "ros2_example_bazel_installed/ros2_example_apps"

    return LaunchDescription(
        [
            launch_ros.actions.Node(
                executable=r.Rlocation(f"{prefix}/eg_talker", source_repo=""),
            ),
            launch_ros.actions.Node(
                executable=r.Rlocation(f"{prefix}/eg_listener", source_repo=""),
            ),
        ]
    )

What it would be good to have

  1. No hardcoded runfiles path strings in launch files
  2. Build-time validation that referenced executables exist
  3. source_repo="" handled transparently, not by the user

Also, the source_repo requirement is a current bug of the current launch file support:

bazel run //ros2_example_apps:roslaunch_eg_py
.
.
.
[INFO] [launch]: All log files can be found below /home/frn/.ros/log/2026-04-07-15-28-43-711973-vader-2564850
[INFO] [launch]: Default logging verbosity is set to INFO
[ERROR] [launch]: Caught exception in launch (see debug for traceback): Caught multiple exceptions when trying to load file of format [py]:
 - ValueError: /home/frn/drake-ros/ros2_example_bazel_installed/ros2_example_apps/eg_launch.py does not lie under the runfiles root /home/frn/.cache/bazel/_bazel_frn/a779afcb46037298559646c7c2f921d4/execroot/_main/bazel-out/k8-fastbuild/bin/ros2_example_apps/roslaunch_eg_py.runfiles
 - InvalidFrontendLaunchFileError: The launch file may have a syntax error, or its format is unknown

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions