Conversation
Based on my analysis of the codebase and the error provided in the GitHub issue, I have identified exactly under what conditions this LateInitializationError is triggered.
The Trigger Condition
This error occurs when the initial connection attempt fails, and then an auto-reconnect is subsequently triggered (either manually via doAutoReconnect() or automatically if configured to
try again).
This explains why the issue isn't seen in the examples or unit tests: those tests invariably ensure the initial connection succeeds before testing the disconnect/reconnect logic.
Why it Happens
1. Missing Initialization on Failure: When a user calls client.connect(), the underlying connection class (e.g., MqttServerNormalConnection) attempts to establish a socket. If this
succeeds, it initializes the messageStream and readWrapper variables before listening to the stream. However, if the initial socket connection fails (e.g., broker is down, network
timeout), the catchError block is triggered, and these fields are never initialized.
2. Re-using the Connection Object: When a reconnection is triggered (like when the user calls doAutoReconnect(...)), the connection handler purposely reuses the existing connection
object because autoReconnectInProgress is true. It then calls the connectAuto() method instead of connect().
3. The Oversight in connectAuto: In all connection classes (e.g., MqttServerNormalConnection, MqttServerSecureConnection, MqttBrowserWsConnection, etc.), the connectAuto() method
successfully establishes the new socket and starts listening (_startListening()), but it completely omits the initialization of messageStream and readWrapper.
4. The Crash: Because the initial connect() failed to initialize them, and connectAuto() didn't initialize them either, they remain uninitialized. As soon as the newly connected broker
sends its first byte of data, onData is fired, attempts to call messageStream.addAll(data), and throws the LateInitializationError.
How to Fix It
To fix this bug, we need to ensure messageStream and readWrapper are initialized in the .then() blocks of the connectAuto() methods across all connection implementation classes, just as
they are in the regular connect() methods.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Based on my analysis of the codebase and the error provided in the GitHub issue, I have identified exactly under what conditions this LateInitializationError is triggered.
The Trigger Condition
This error occurs when the initial connection attempt fails, and then an auto-reconnect is subsequently triggered (either manually via doAutoReconnect() or automatically if configured to
try again).
This explains why the issue isn't seen in the examples or unit tests: those tests invariably ensure the initial connection succeeds before testing the disconnect/reconnect logic.
Why it Happens
How to Fix It
To fix this bug, we need to ensure messageStream and readWrapper are initialized in the .then() blocks of the connectAuto() methods across all connection implementation classes, just as
they are in the regular connect() methods.