Version
BehaviorTree.CPP 4.9.0
Describe the bug
When LoopNode<T> receives a dynamic input port mapped to a blackboard entry containing std::vector<T>, the first execution works correctly, but a second execution of the same tree instance may not reload the new vector value.
In my case:
- an upstream node writes a new
std::vector<T> to the blackboard output port
LoopNode<T> consumes it correctly on the first run
- on the second run, the upstream node again writes the correct new vector
- however,
LoopNode<T> behaves as if the queue is empty or keeps using the previous internal queue state
This seems to happen because current_queue_ is preserved across executions, and for dynamic vector input the code only converts std::vector<T> into std::deque<T> when !current_queue_.
As a result, on the second execution, if current_queue_ is already non-null, the new vector from the blackboard is not reloaded.
Expected behavior
When the same tree instance starts a fresh execution, LoopNode<T> should reload the current dynamic input value from the blackboard.
If the input port contains a new std::vector<T>, it should be reflected in the loop execution.
Actual behavior
The first execution works, but the second execution may immediately see an empty queue or behave as if the previous internal queue state is still active.
Minimal reasoning about root cause
The problematic pattern appears to be:
if(status() == NodeStatus::IDLE)
{
child_running_ = false;
if(static_queue_)
{
current_queue_ = std::make_shared<std::deque<T>>();
*current_queue_ = *static_queue_;
}
}
and later:
auto queue_result = any_ref.get()->tryCast<SharedQueue<T>>();
if(queue_result)
{
current_queue_ = queue_result.value();
}
else if(!current_queue_)
{
auto vec_result = any_ref.get()->tryCast<std::vector<T>>();
if(vec_result)
{
const auto& vec = vec_result.value();
current_queue_ = std::make_shared<std::deque<T>>(vec.begin(), vec.end());
}
}
If the input is dynamic std::vector<T>:
- first run: current_queue_ is null, so the vector is converted and used
- second run: current_queue_ is still non-null, so the new vector is not reloaded
Reproduction scenario
- Use a tree with an upstream node that writes a
std::vector<T> output to a blackboard(Output port) entry.
- Feed that entry to
LoopNode<T> through a remapped input/inout port.
- Run the tree once until completion.
- Without destroying the tree instance, update the upstream input again so that the upstream node writes a new vector.
- Run the tree again.
- Observe that the upstream node outputs the correct new vector, but
LoopNode<T> does not reflect the new value.
Here is my test xml:

In above image, {scenario_pair_list} is the std::vector<T>
What I confirmed
- The upstream node definitely writes the expected vector on the second run.
- The issue disappears if I modify
LoopNode so that current_queue_ is reset when a fresh execution starts.
- For example, resetting
current_queue_ at the beginning of a fresh IDLE execution resolves the problem in my setup.
Example fix that works locally:
if(status() == NodeStatus::IDLE)
{
child_running_ = false;
current_queue_.reset();
if(static_queue_)
{
current_queue_ = std::make_shared<std::deque<T>>();
*current_queue_ = *static_queue_;
}
}
Question
Is this intended behavior for dynamic std::vector<T> inputs, or should LoopNode<T> reload the blackboard value on each fresh execution of the node?
Version
BehaviorTree.CPP 4.9.0
Describe the bug
When
LoopNode<T>receives a dynamic input port mapped to a blackboard entry containingstd::vector<T>, the first execution works correctly, but a second execution of the same tree instance may not reload the new vector value.In my case:
std::vector<T>to the blackboard output portLoopNode<T>consumes it correctly on the first runLoopNode<T>behaves as if the queue is empty or keeps using the previous internal queue stateThis seems to happen because
current_queue_is preserved across executions, and for dynamic vector input the code only convertsstd::vector<T>intostd::deque<T>when!current_queue_.As a result, on the second execution, if
current_queue_is already non-null, the new vector from the blackboard is not reloaded.Expected behavior
When the same tree instance starts a fresh execution,
LoopNode<T>should reload the current dynamic input value from the blackboard.If the input port contains a new
std::vector<T>, it should be reflected in the loop execution.Actual behavior
The first execution works, but the second execution may immediately see an empty queue or behave as if the previous internal queue state is still active.
Minimal reasoning about root cause
The problematic pattern appears to be:
and later:
If the input is dynamic
std::vector<T>:Reproduction scenario
std::vector<T>output to a blackboard(Output port) entry.LoopNode<T>through a remapped input/inout port.LoopNode<T>does not reflect the new value.Here is my test xml:

In above image,
{scenario_pair_list}is thestd::vector<T>What I confirmed
LoopNodeso thatcurrent_queue_is reset when a fresh execution starts.current_queue_at the beginning of a freshIDLEexecution resolves the problem in my setup.Example fix that works locally:
Question
Is this intended behavior for dynamic
std::vector<T>inputs, or shouldLoopNode<T>reload the blackboard value on each fresh execution of the node?