Skip to content

EventsCBGExecutor shutdown + ComponentManager destructor cause double remove and runtime_error on shutdown #3186

Description

@liangzhenjie

Description

When running a component container using ExecutorType::EventsCBG, during shutdown the EventsCBGExecutor::shutdown() path removes all added nodes via remove_all_nodes_and_callback_groups(), which calls remove_node() on each added node. Later the ComponentManager destructor also iterates over its node_wrappers_ and calls executor->remove_node(...) for each wrapped node. This leads to a double-remove of the same node on the executor and triggers the runtime_error thrown in EventsCBGExecutor::remove_node():

throw std::runtime_error(
std::string("Node '") + node_ptr->get_fully_qualified_name() +
"' needs to be associated with an executor.");

This is a deterministic problem in the common shutdown sequence: executor shutdown removes the nodes first, then ComponentManager::~ComponentManager attempts to remove them again.

Steps to reproduce

  1. Start a component container that loads components (ComponentManager + EventsCBG executor).
  2. Trigger shutdown (e.g. Ctrl+C) so that EventsCBGExecutor::shutdown() runs.
  3. Observe that executor::remove_node() is called during shutdown and then ComponentManager::~ComponentManager later calls remove_node again, resulting in the runtime_error.

Observed behavior

  • An exception (runtime_error) may be thrown during process shutdown because of double remove of nodes.

Expected behavior

  • Shutdown should not produce an exception. Double removal of the same node should be tolerated (no throw) or ComponentManager should avoid attempting to remove nodes already removed by the executor during shutdown.

Suggested fixes

  1. Short-term / minimal change: In ComponentManager::~ComponentManager, wrap exec->remove_node(...) calls in try/catch and ignore/log exceptions from double-remove so shutdown is not noisy or abortive.

  2. More robust fix: Change executor::remove_node() to be idempotent and not throw when a node is already unassociated; instead log a warning and return. Alternatively, coordinate shutdown so ComponentManager knows nodes were removed by executor (e.g. clear/notify node_wrappers_ during executor shutdown).

Files/locations of interest

  • rclcpp/src/rclcpp/executors/events_cbg_executor/events_cbg_executor.cpp (remove_node implementation contains the throw)
  • rclcpp_components/src/component_manager.cpp (ComponentManager::~ComponentManager calls exec->remove_node for node_wrappers_)

Additional notes

  • This appears to be a common and deterministic sequence in the normal Ctrl+C shutdown flow, so it is likely to affect users running component containers with EventsCBG executor.
  • A small safe patch in ComponentManager (try/catch around remove_node in destructor) would mitigate the immediate issue while a more semantically-correct fix is implemented.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions