Skip to content

[flutter_tools] Handle all DartDevelopmentServiceExceptions gracefully in resident web runner - #191183

Merged
auto-submit[bot] merged 2 commits into
flutter:masterfrom
bkonyi:crash-dds-websocket-upgrade-failed
Aug 18, 2026
Merged

auto-submit[bot] merged 2 commits into
flutter:masterfrom
bkonyi:crash-dds-websocket-upgrade-failed

Conversation

@bkonyi

@bkonyi bkonyi commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Description

This PR ensures that ResidentWebRunner catches all variants of DartDevelopmentServiceException during startup, rather than just failedToStartError.

When DDS fails to establish a WebSocket connection or upgrade the connection to DWDS (e.g., if the target browser exits prematurely or rejects the handshake), package:dds throws DartDevelopmentServiceException.connectionIssue(...) with errorCode = DartDevelopmentServiceException.connectionError (Code 3), rather than failedToStartError (Code 2).

Previously, ResidentWebRunner only caught failedToStartError and rethrew all other DartDevelopmentServiceExceptions, which caused the CLI to crash with an unhandled top-level exception.

With this change, we catch all DartDevelopmentServiceExceptions, log the error details with stack trace, perform necessary cleanup, and gracefully exit via throwToolExit(kExitMessage).

Related Issues

Fixes #191179

Tests

Added a new unit test in resident_web_runner_test.dart:

  • Does not crash if DDS fails to upgrade WebSocket during startup

…y in resident web runner

When DDS fails to establish a WebSocket connection or upgrade the connection
to DWDS (e.g. if the target browser exits prematurely or rejects the handshake),
package:dds throws DartDevelopmentServiceException with errorCode connectionError
rather than failedToStartError.

ResidentWebRunner previously only caught failedToStartError and rethrew all other
DartDevelopmentServiceExceptions, which caused the CLI to crash with an unhandled
top-level exception.

This change catches all DartDevelopmentServiceExceptions in ResidentWebRunner.run,
logs the error, and gracefully exits via throwToolExit(kExitMessage).
@github-actions github-actions Bot added the tool Affects the "flutter" command-line tool. See also t: labels. label Aug 16, 2026
@bkonyi bkonyi added the CICD Run CI/CD label Aug 16, 2026
@bkonyi
bkonyi marked this pull request as ready for review August 17, 2026 17:56

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request modifies ResidentWebRunner to catch DartDevelopmentServiceException during startup, log the error and stack trace, and throw a tool exit. It also adds a unit test to verify that the runner does not crash when DDS fails to upgrade the WebSocket. Feedback points out that logging all DartDevelopmentServiceExceptions introduces a regression by printing noisy stack traces for expected startup failures (specifically failedToStartError). It is recommended to preserve the quiet behavior for expected failures and use error.message instead of error.toString().

Comment on lines +409 to +414
} on DartDevelopmentServiceException catch (error, stackTrace) {
// The application may have started shutting down before DDS was able to finish establishing
// its connection to DWDS. Don't treat this as an unhandled exception.
appFailedToStart();
if (error.errorCode == DartDevelopmentServiceException.failedToStartError) {
throwToolExit(kExitMessage);
}
rethrow;
_logger.printError(error.toString(), stackTrace: stackTrace);
throwToolExit(kExitMessage);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Previously, when error.errorCode == DartDevelopmentServiceException.failedToStartError, the runner would call throwToolExit(kExitMessage) directly without printing any error message or stack trace to the console. This is because failedToStartError is an expected failure mode where additional stack traces are unnecessary and noisy for the user.

With the current changes, all DartDevelopmentServiceExceptions (including failedToStartError) will print the error and stack trace via _logger.printError, which introduces a regression in the user experience by printing noisy stack traces for expected startup failures.

We should preserve the quiet behavior for failedToStartError and only log the error/stack trace for other unexpected DartDevelopmentServiceException error codes. Also, using error.message is cleaner than error.toString() as it avoids the class name prefix.

Suggested change
} on DartDevelopmentServiceException catch (error, stackTrace) {
// The application may have started shutting down before DDS was able to finish establishing
// its connection to DWDS. Don't treat this as an unhandled exception.
appFailedToStart();
if (error.errorCode == DartDevelopmentServiceException.failedToStartError) {
throwToolExit(kExitMessage);
}
rethrow;
_logger.printError(error.toString(), stackTrace: stackTrace);
throwToolExit(kExitMessage);
} on DartDevelopmentServiceException catch (error, stackTrace) {
// The application may have started shutting down before DDS was able to finish establishing
// its connection to DWDS. Don't treat this as an unhandled exception.
appFailedToStart();
if (error.errorCode != DartDevelopmentServiceException.failedToStartError) {
_logger.printError(error.message, stackTrace: stackTrace);
}
throwToolExit(kExitMessage);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in commit f86ca0c to preserve quiet behavior for failedToStartError and log error.message with stack trace for unexpected error codes.

@bkonyi
bkonyi requested a review from chingjun August 17, 2026 18:38
@bkonyi bkonyi added the autosubmit Merge PR when tree becomes green via auto submit App label Aug 18, 2026
@auto-submit
auto-submit Bot added this pull request to the merge queue Aug 18, 2026
Merged via the queue into flutter:master with commit 3d2c811 Aug 18, 2026
20 of 21 checks passed
@flutter-dashboard flutter-dashboard Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Aug 18, 2026
@bkonyi
bkonyi deleted the crash-dds-websocket-upgrade-failed branch August 18, 2026 23:09
@bkonyi bkonyi added cp: stable cherry pick this pull request to stable release candidate branch and removed cp:stable labels Aug 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CICD Run CI/CD cp: stable cherry pick this pull request to stable release candidate branch tool Affects the "flutter" command-line tool. See also t: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[flutter_tools] Unhandled DartDevelopmentServiceException when WebSocket upgrade fails during DDS startup in ResidentWebRunner

2 participants