Skip to content

fix(mqtt): make the MQTT client-id unique per connection#5755

Merged
jamesarich merged 1 commit into
meshtastic:mainfrom
jamesarich:claude/naughty-rhodes-a35d9c
Jun 9, 2026
Merged

fix(mqtt): make the MQTT client-id unique per connection#5755
jamesarich merged 1 commit into
meshtastic:mainfrom
jamesarich:claude/naughty-rhodes-a35d9c

Conversation

@jamesarich

Copy link
Copy Markdown
Collaborator

What

Append a per-connection random Uuid suffix to the MQTT proxy/probe client-id.

Why

The client-id was MeshtasticAndroidMqttProxy-$myId (and …Probe-$myId), where myId is the node id — and is null → the literal unknown until the local node record loads. That isn't unique per connecting client:

  • Every client whose node identity hasn't resolved yet shares the identical MeshtasticAndroidMqttProxy-unknown, so on the public broker they continuously evict one another.
  • A replacement client after a BLE flap briefly reuses the same node-scoped id as the one still tearing down.

When a duplicate client-id connects, the broker evicts the previous holder with SESSION_TAKEN_OVER (0x8E); the two clients take the session back and forth — a reconnect storm. That storm is the trigger for the top io.ktor TLS-write crash on 2.7.14 (fixed independently in the mqtt-client library — this removes the trigger).

A radio only accepts one app connection at a time, so there is never a legitimate case for two clients to share an id — making a unique suffix unambiguously safe.

Change

  • MQTTRepositoryImpl (proxy) and MqttManagerImpl (probe): append -${Uuid.random()} to the client-id. Generated once per MqttClient/probe construction, so the id is captured for that client's lifetime — auto-reconnects keep the same id (no self-eviction), while a brand-new client after a flap gets a fresh one.
  • cleanStart = true (unchanged default), so there is no durable session to preserve — a per-connection id is fine and avoids a stable broker-trackable identifier.
  • MQTTRepositoryImplTest: assert the client-id prefix instead of exact equality.

Testing

spotlessCheck detekt kmpSmokeCompile :core:network:allTests :core:data:allTests all pass.

🤖 Generated with Claude Code

The proxy/probe client-id was "MeshtasticAndroidMqttProxy-$myId", where
myId is the node id and is null ("unknown") until the local node record
loads. That is not unique per client: clients sharing a node id — and the
whole "unknown" pool on the public broker — present identical client-ids.
A broker evicts the previous holder (SESSION_TAKEN_OVER) when a duplicate
id connects, producing the reconnect storms behind the top io.ktor
TLS-write crash on 2.7.14.

Append a per-connection random Uuid suffix at each MqttClient/probe
construction (captured for the client's lifetime, so auto-reconnects stay
stable; a replacement client after a flap gets a fresh id). cleanStart is
true, so no durable session is lost.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added the bugfix PR tag label Jun 9, 2026
@jamesarich jamesarich added this pull request to the merge queue Jun 9, 2026
Merged via the queue into meshtastic:main with commit 65e9374 Jun 9, 2026
18 checks passed
@jamesarich jamesarich deleted the claude/naughty-rhodes-a35d9c branch June 9, 2026 16:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugfix PR tag

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant