Skip to content

fix(ros2-bridge): don't panic on zero-field message types (std_msgs/Empty) - #2864

Draft
phil-opp wants to merge 1 commit into
mainfrom
claude/clever-wright-tjnjf8-ros2-empty-msg-panic
Draft

fix(ros2-bridge): don't panic on zero-field message types (std_msgs/Empty)#2864
phil-opp wants to merge 1 commit into
mainfrom
claude/clever-wright-tjnjf8-ros2-empty-msg-panic

Conversation

@phil-opp

Copy link
Copy Markdown
Collaborator

Summary

Fixes #2804.

Deserializing a ROS 2 message type with zero fields (e.g. std_msgs/msg/Empty) panicked in the ros2-bridge CDR→Arrow conversion:

called `Result::unwrap()` on an `Err` value: InvalidArgumentError("use StructArray::try_new_with_length or StructArray::new_empty_fields to create a struct array with no fields so that the length can be set correctly")

StructArray::from(Vec<..>) panics on an empty field vec because the array length is ambiguous with no columns. Since the deserializer runs inside the subscription take path while a RustDDS cache lock is held, the panic poisoned the DDS cache mutex and then killed the participant event loop — silently taking down every subscription on the participant (0 Hz on all topics) after a single stray Empty message.

Changes

  • deserialize/mod.rs (the take path) and serialize/defaults.rs (default-value construction) now build a length‑1 empty‑fields struct via StructArray::new_empty_fields(1, None) when there are no fields, instead of fields.into(). This mirrors the pattern already used in the crate's default-value test code.
  • Added a regression test empty_message_deserializes that deserializes a zero‑field message and asserts it produces a single struct row with no columns.

Testing

  • cargo test -p dora-ros2-bridge-arrow — 16 passed, incl. the new regression test
  • cargo clippy -p dora-ros2-bridge-arrow -- -D warnings — clean
  • cargo fmt --all -- --check — clean

Generated by Claude Code

…mpty)

Deserializing a ROS 2 message type with zero fields (e.g.
`std_msgs/msg/Empty`) panicked in the CDR->Arrow conversion because
`StructArray::from(Vec<..>)` panics on an empty field vec — the array
length is ambiguous with no columns.

Because the deserializer runs inside the subscription take path while a
RustDDS cache lock is held, that panic poisoned the DDS cache mutex and
subsequently killed the participant event loop, silently taking down
every subscription on the participant (0 Hz on all topics) after a
single stray Empty message.

Guard both the deserialize path (`deserialize/mod.rs`) and the default
value path (`serialize/defaults.rs`) to build a length-1 empty-fields
struct via `StructArray::new_empty_fields(1, None)` when there are no
fields, matching the pattern already used in the defaults test code.

Adds a regression test that deserializes a zero-field message.

Fixes #2804

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PpY25UTvkyfgyTaJYcAQ7v
@trunk-io

trunk-io Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Merging to main in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here

Copy link
Copy Markdown
Collaborator Author

Automated review by Claude — this is a fully automated review; no human has vetted it.

No issues found. StructArray::new_empty_fields(1, None) is the right way to build a zero-column struct with a defined length, and both the take-path (deserialize/mod.rs) and default-construction path (serialize/defaults.rs) are covered. The regression test exercises the real deserializer end-to-end on an empty CDR body and asserts a single zero-column row, so it genuinely guards the previously-panicking path.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ros2-bridge: empty message types (std_msgs/Empty) panic the CDR->Arrow deserializer and kill the DDS participant

2 participants