Skip to content

[flutter_tools] Fix DTD "Stream already subscribed" error and wait for analysis over DTD in widget preview - #192930

Merged
auto-submit[bot] merged 10 commits into
flutter:masterfrom
bkonyi:investigate_flutter_issue_192424
Oct 1, 2026
Merged

auto-submit[bot] merged 10 commits into
flutter:masterfrom
bkonyi:investigate_flutter_issue_192424

Conversation

@bkonyi

@bkonyi bkonyi commented Sep 17, 2026 •

Copy link
Copy Markdown
Contributor

Description

During widget preview startup or file updates:

  1. Concurrent calls to retrieve previews or wait for analysis (e.g., initial command startup racing with file watcher events) could concurrently invoke _waitForLspService(), causing duplicate streamListen calls to the Dart Tooling Daemon. DTD throws JSON-RPC error 103 (Stream already subscribed) when a client attempts to subscribe to a stream it is already listening to.
  2. WidgetPreviewDtdServices previously considered the Lsp service ready as soon as any Lsp method was registered on DTD (or upon receiving the first ServiceRegistered event for Lsp). Because the analysis server registers its LSP methods sequentially before posting an initialized event on the Lsp stream, calls to Lsp.dart/workspace/analysis/complete or Lsp.dart/workspace/getFlutterWidgetPreviews could race ahead of their registration and fail with -32601 (method not found).
  3. When connecting to a pre-existing analysis server over DTD (--dtd-url), LspPreviewDetector.analysisServer is null, causing analysisServer?.waitForAnalysis() calls during startup and file updates to be no-ops.

This change:

  • Deduplicates in-flight calls to _waitForLspService() using a shared future (_waitForLspServiceFuture) so concurrent callers await the same LSP registration check instead of issuing duplicate DTD requests.
  • Separates lspServiceAvailable (whether an analysis server has begun registering Lsp services on DTD) from _allLspServicesRegistered (whether all required widget preview LSP methods in kRequiredLspServices are registered), and updates _waitForLspServiceHelper() to listen for the initialized event on the Lsp stream before checking getRegisteredServices().
  • Consolidates LSP DTD calls into _callLspService() and removes the kMethodNotFound polling loop now that _waitForLspService() ensures all required LSP methods are registered.
  • Safely catches and ignores RpcErrorCodes.kStreamAlreadySubscribed on streamListen calls in WidgetPreviewDtdServices (safeStreamListen).
  • Adds WidgetPreviewDtdServices.waitForAnalysis() (invoking Lsp.dart/workspace/analysis/complete over DTD), unifies LspPreviewDetector.waitForAnalysis() so widget preview waits for analysis completion on both tool-managed and pre-existing analysis servers, and moves the startup waitForAnalysis() call inside the DTD error-handling try / catch block in WidgetPreviewStartCommand.
  • Adds hermetic regression tests covering concurrent/pre-subscribed DTD streams, partial vs. full LSP service registration (Lsp.initialized), and waiting for analysis over DTD.

Fixes #192424

Pre-launch Checklist

…review

During widget preview startup, concurrent calls to retrieve previews
(e.g., initial command startup racing with file watcher events) could both
call `_waitForLspService()`, causing concurrent `streamListen` calls to the
Dart Tooling Daemon on the `Service` stream. DTD throws JSON-RPC error 103
(`Stream already subscribed`) when a client attempts to subscribe to a
stream it is already listening to.

This change:
- Deduplicates in-flight calls to `_waitForLspService()` using a shared
  future so concurrent callers await the same LSP registration event
  instead of issuing duplicate DTD requests.
- Safely catches and ignores `RpcErrorCodes.kStreamAlreadySubscribed` on
  `streamListen` calls in `WidgetPreviewDtdServices`.
- Adds hermetic regression tests covering concurrent and pre-subscribed
  stream scenarios.

Fixes flutter#192424
@github-actions github-actions Bot added the tool Affects the "flutter" command-line tool. See also t: labels. label Sep 17, 2026
@bkonyi bkonyi added the CICD Run CI/CD label Sep 18, 2026
@bkonyi
bkonyi marked this pull request as ready for review September 18, 2026 14:53

@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 introduces changes to WidgetPreviewDtdServices to handle concurrent calls to _waitForLspService and avoid stream already subscribed exceptions. It caches the future of _waitForLspService and adds a safeStreamListen extension on DartToolingDaemon to ignore kStreamAlreadySubscribed RPC exceptions. Unit tests are added to verify these behaviors. Feedback suggests refactoring the immediately invoked asynchronous function expression (IIFE) in _waitForLspService to use standard control flow with the cached future for better readability.

Comment thread packages/flutter_tools/lib/src/widget_preview/dtd_services.dart
@bkonyi
bkonyi requested a review from srawlins September 18, 2026 14:54
@bkonyi bkonyi added the t: cp-candidate A PR that should be considered for a cherry-pick upon landing. label Sep 18, 2026
@bkonyi bkonyi changed the title [flutter_tools] Fix DTD "Stream already subscribed" error in widget preview [flutter_tools] Fix DTD "Stream already subscribed" error and wait for analysis over DTD in widget preview Sep 21, 2026
@bkonyi
bkonyi requested a review from DanTup September 21, 2026 21:08
srawlins
srawlins previously approved these changes Sep 22, 2026

@srawlins srawlins 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.

Again, nice tests

@DanTup DanTup 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.

Awesome, thank you! I'll try running a branch of my E2E tests against your fork/branch and see if this resolves the remaining flakes :-)

@DanTup DanTup 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.

Oh, I'm seeing failures here using your fork:

[9:21:01 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"Oops; flutter has exited unexpectedly: \"JSON-RPC error -32601 (method not found): Unknown method \"Lsp.dart/workspace/analysis/complete\".\"."}}]

I'm just debugging, will post back when I understand what's happening...

Comment thread packages/flutter_tools/lib/src/widget_preview/dtd_services.dart Outdated
srawlins
srawlins previously approved these changes Sep 25, 2026
DanTup
DanTup previously approved these changes Sep 26, 2026

@DanTup DanTup 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.

Thanks! The changes LGTM. I will test my E2E tests against this on Monday (I'll leave it to you if you want to wait for the result of that, or land this and if any issues do come up address seperately).

@DanTup

DanTup commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

Unfortunately still seeing something wrong here on the GH bots:

[9:27:19 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"status","message":"Waiting for analysis server to register Lsp service with DTD..."}}]
[9:27:49 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"warning","message":"Timed out waiting for the Lsp service to be registered with DTD."}}]
[9:27:49 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"Failed to retrieve widget previews from the Dart Tooling Daemon (DTD). Ensure that the analysis server is running and reachable. Details: TimeoutException after 0:00:30.000000: Future not completed"}}]

I can see we're passing the right DTD URI:

[9:27:13 AM] [FlutterWidgetPreview] [Info] Spawning /home/runner/work/E2E-Tests/E2E-Tests/flutter/bin/flutter with args ["widget-preview","start","--machine","--web-server","--dtd-url","ws://127.0.0.1:43807/wqWEMJ32jZg=","--devtools-server-address","http://127.0.0.1:9100/"]

And in the analysis server log:

1790587632420:Req:{"jsonrpc"::"2.0","id"::1,"method"::"dart/connectToDtd","params"::{"uri"::"ws:://127.0.0.1::43807/wqWEMJ32jZg=","registerExperimentalHandlers"::false},"clientRequestTime"::1790587632419}
1790587632422:Res:{"id"::1,"jsonrpc"::"2.0","result"::null}

The times of the server request are 09:27:12.420 and 09:27:12.422.

I'll will add some more verbose logging to try and track this down and post back.

@DanTup

DanTup commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

@bkonyi it's not the issue I noted above (still trying to repro that with verbose logging, it seems intermittent), but I hit another issue where a new analysis server was spawned despite passing a DTD URI:

[10:04:08 AM] [FlutterWidgetPreview] [Info] Spawning /home/runner/work/E2E-Tests/E2E-Tests/flutter/bin/flutter with args ["widget-preview","start","--machine","--web-server","--dtd-url","ws://127.0.0.1:37825/sJTNlYnAN9A=","--devtools-server-address","http://127.0.0.1:9100/"]
[...]
[10:04:14 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"status","message":"Launching analysis server..."}}]

I think the logic here might be wrong:

if (!dtd.lspServiceAvailable) {
logger.printStatus('Launching analysis server...');

It will spawn an analysis server if "the DTD LSP service is not yet available", even if it might become available seconds later?

@DanTup

DanTup commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

@bkonyi despite many tries, I haven't been able to repro the first issue I posted about this morning above (I'm running with more verbose logging added to a copy of your branch, but it never happens). However, in addition to the issue noted above, I do also seem other weird errors (I tried rebasing the branch on master to see if that help, but it did not):

[10:51:56 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"../../../../flutter/packages/flutter/lib/src/rendering/binding.dart:74:14: Error: Type 'ui.TextureFrameAvailableCallback' not found."}}]
[10:51:56 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"  final List<ui.TextureFrameAvailableCallback> _textureFrameAvailableCallbacks ="}}]
[10:51:56 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"}}]
[10:51:56 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"../../../../flutter/packages/flutter/lib/src/rendering/binding.dart:83:41: Error: Type 'ui.TextureFrameAvailableCallback' not found."}}]
[10:51:56 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"  void addTextureFrameAvailableCallback(ui.TextureFrameAvailableCallback handler) {"}}]
[10:51:56 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"}}]
[10:51:56 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"../../../../flutter/packages/flutter/lib/src/rendering/binding.dart:89:44: Error: Type 'ui.TextureFrameAvailableCallback' not found."}}]

I don't know if either of these issues are related to this PR, so I can file them separately if you think this PR is still a net improvement.

@bkonyi
bkonyi dismissed stale reviews from DanTup and srawlins via 4fab5f7 September 28, 2026 12:49
@DanTup

DanTup commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

@bkonyi I just tried again with the latest commit you pushed, but I got this error again:

[2:20:54 PM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"status","message":"Launching analysis server..."}}]
[2:20:56 PM] [FlutterWidgetPreview] [Error] 
[2:20:56 PM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"Oops; flutter has exited unexpectedly: \"Unknown method dart/workspace/analysis/complete\"."}}]

Full log is here:

widgetpreview.txt

GH Actions results here:

https://github.com/Dart-Code/E2E-Tests/actions/runs/36434945313/job/108970314634

I double-checked to ensure it was the right code, and it shows:

Run git clone -b investigate_flutter_issue_192424 https://github.com/bkonyi/flutter
Cloning into 'flutter'...
[!] Flutter (Channel [user-branch], 3.41.1-0.0.pre-8092, on Ubuntu 24.04.5 LTS 6.17.0-1022-azure, locale C.UTF-8)
    ! Flutter version 3.41.1-0.0.pre-8092 on channel [user-branch] at /home/runner/work/E2E-Tests/E2E-Tests/flutter
      Currently on an unknown channel. Run `flutter channel` to switch to an official channel.

Edit: I'll note that I think it's spawning an analysis server when it shouldn't, which may or may not be the cause of the error.

…s not provided

When --dtd-url is provided, an external tool (such as an IDE) owns the DTD
instance and connects its own analysis server. Because analysis_server's
dart/connectToDtd responds before Lsp services finish registering on DTD,
checking dtd.lspServiceAvailable during LspPreviewDetector.initialize()
raced with service registration and caused flutter_tools to spawn a
duplicate analysis server.

Only launch an internal analysis server and DTD instance when dtd.dtdUri
is null, and rely on dtd.waitForAnalysis() to wait for the external
analysis server to finish registering the Lsp service on DTD.
@DanTup

DanTup commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

@bkonyi I'm still hitting this error when trying to run the tests against your branch, but I'm struggling to understand why. It doesn't seem to repro locally. I feel like something (sky_engine?) is out of date (that's where these references seem to go when I open it locally - where I cannot repro the error), but I don't know how that could be. On the bots we're doing:

    - name: Checkout Flutter SDK
      run: git clone -b debug-new-pr https://github.com/DanTup/flutter

    - name: Add Flutter SDK to PATH
      run: echo "${{github.workspace}}/flutter/bin" >> $GITHUB_PATH

    - run: dart --disable-analytics
    - run: flutter --disable-analytics
    - run: flutter update-packages
    - run: flutter doctor

My debug-new-pr branch is just a copy of yours but with some additional logging (but I saw the same error with your branch directly). I did git push --tags to my fork in case any part of it needed the latest tags, but that made no difference.

[11:14:01 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"status","message":"Launching lib/main.dart on Web Server in debug mode..."}}]
[11:14:02 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"status","message":"Waiting for connection from debug service on Web Server..."}}]
[11:14:04 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"../../../../flutter/packages/flutter/lib/src/rendering/binding.dart:74:14: Error: Type 'ui.TextureFrameAvailableCallback' not found."}}]
[11:14:04 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"  final List<ui.TextureFrameAvailableCallback> _textureFrameAvailableCallbacks ="}}]
[11:14:04 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"}}]
[11:14:04 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"../../../../flutter/packages/flutter/lib/src/rendering/binding.dart:83:41: Error: Type 'ui.TextureFrameAvailableCallback' not found."}}]
[11:14:04 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"  void addTextureFrameAvailableCallback(ui.TextureFrameAvailableCallback handler) {"}}]
[11:14:04 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"}}]
[11:14:04 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"../../../../flutter/packages/flutter/lib/src/rendering/binding.dart:89:44: Error: Type 'ui.TextureFrameAvailableCallback' not found."}}]
[11:14:04 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"  void removeTextureFrameAvailableCallback(ui.TextureFrameAvailableCallback handler) {"}}]
[11:14:04 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"}}]
[11:14:06 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"../../../../flutter/packages/flutter/lib/src/rendering/binding.dart:63:9: Error: The setter 'onTextureFrameAvailable' isn't defined for the type 'PlatformDispatcher'."}}]
[11:14:06 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":" - 'PlatformDispatcher' is from 'dart:ui'."}}]
[11:14:06 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"Try correcting the name to the name of an existing setter, or defining a setter or field named 'onTextureFrameAvailable'."}}]
[11:14:06 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"      ..onTextureFrameAvailable = handleTextureFrameAvailable"}}]
[11:14:06 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"        ^^^^^^^^^^^^^^^^^^^^^^^"}}]
[11:14:06 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"../../../../flutter/packages/flutter/lib/src/rendering/binding.dart:64:9: Error: The setter 'onMarkAllViewsNeedRender' isn't defined for the type 'PlatformDispatcher'."}}]
[11:14:06 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":" - 'PlatformDispatcher' is from 'dart:ui'."}}]
[11:14:06 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"Try correcting the name to the name of an existing setter, or defining a setter or field named 'onMarkAllViewsNeedRender'."}}]
[11:14:06 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"      ..onMarkAllViewsNeedRender = handleMarkAllViewsNeedRender;"}}]
[11:14:06 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"        ^^^^^^^^^^^^^^^^^^^^^^^^"}}]
[11:14:06 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"../../../../flutter/packages/flutter/lib/src/rendering/binding.dart:74:17: Error: 'TextureFrameAvailableCallback' isn't a type."}}]
[11:14:06 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"  final List<ui.TextureFrameAvailableCallback> _textureFrameAvailableCallbacks ="}}]
[11:14:06 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"}}]
[11:14:06 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"../../../../flutter/packages/flutter/lib/src/rendering/binding.dart:75:11: Error: 'TextureFrameAvailableCallback' isn't a type."}}]
[11:14:06 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"      <ui.TextureFrameAvailableCallback>[];"}}]
[11:14:06 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"}}]
[11:14:06 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"../../../../flutter/packages/flutter/lib/src/rendering/binding.dart:83:44: Error: 'TextureFrameAvailableCallback' isn't a type."}}]
[11:14:06 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"  void addTextureFrameAvailableCallback(ui.TextureFrameAvailableCallback handler) {"}}]
[11:14:06 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"}}]
[11:14:06 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"../../../../flutter/packages/flutter/lib/src/rendering/binding.dart:89:47: Error: 'TextureFrameAvailableCallback' isn't a type."}}]
[11:14:06 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"  void removeTextureFrameAvailableCallback(ui.TextureFrameAvailableCallback handler) {"}}]
[11:14:06 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"}}]
[11:14:06 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"../../../../flutter/packages/flutter/lib/src/rendering/binding.dart:105:36: Error: 'TextureFrameAvailableCallback' isn't a type."}}]
[11:14:06 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"    for (final callback in List<ui.TextureFrameAvailableCallback>.of("}}]
[11:14:06 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"}}]
[11:14:16 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"Unhandled exception:"}}]
[11:14:16 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"Unsupported operation: Unsupported invalid type InvalidType(<invalid>) (InvalidType). Encountered while compiling file:///home/runner/work/E2E-Tests/E2E-Tests/flutter/packages/flutter/lib/src/rendering/binding.dart, which contains the type: InterfaceType(JSArray<<invalid>>)."}}]
[11:14:16 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"#0      LibraryCompiler._typeCompilationError (package:dev_compiler/src/kernel/compiler_new.dart:4496)"}}]
[11:14:16 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"#1      LibraryCompiler._emitType (package:dev_compiler/src/kernel/compiler_new.dart:4461)"}}]
[11:14:16 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"#2      LibraryCompiler._emitList (package:dev_compiler/src/kernel/compiler_new.dart:8760)"}}]
[11:14:16 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"#3      LibraryCompiler.visitListLiteral (package:dev_compiler/src/kernel/compiler_new.dart:8743)"}}]
[11:14:16 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"#4      ListLiteral.accept (package:kernel/src/ast/expressions.dart:4550)"}}]
[11:14:16 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"#5      LibraryCompiler._visitExpression (package:dev_compiler/src/kernel/compiler_new.dart:5142)"}}]
[11:14:16 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"#6      LibraryCompiler._visitInitializer (package:dev_compiler/src/kernel/compiler_new.dart:2741)"}}]
[11:14:16 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"#7      LibraryCompiler._emitFieldInit (package:dev_compiler/src/kernel/compiler_new.dart:2684)"}}]
[11:14:16 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"#8      LibraryCompiler._initializeFields (package:dev_compiler/src/kernel/compiler_new.dart:2712)"}}]
[11:14:16 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"#9      LibraryCompiler._defineConstructors (package:dev_compiler/src/kernel/compiler_new.dart:2051)"}}]
[11:14:16 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"#10     LibraryCompiler._emitClassDeclaration (package:dev_compiler/src/kernel/compiler_new.dart:1497)"}}]
[11:14:16 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"#11     LibraryCompiler._emitClass (package:dev_compiler/src/kernel/compiler_new.dart:1436)"}}]
[11:14:16 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"#12     List.forEach (dart:core-patch/growable_array.dart:428)"}}]
[11:14:16 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"#13     LibraryCompiler._emitLibrary (package:dev_compiler/src/kernel/compiler_new.dart:1358)"}}]
[11:14:16 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"#14     LibraryCompiler.emitLibrary (package:dev_compiler/src/kernel/compiler_new.dart:970)"}}]
[11:14:16 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"#15     LibraryBundleCompiler.emitModule (package:dev_compiler/src/kernel/compiler_new.dart:166)"}}]
[11:14:16 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"#16     IncrementalJavaScriptBundler.compile (package:frontend_server/src/javascript_bundle.dart:366)"}}]
[11:14:16 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"#17     FrontendCompiler.writeJavaScriptBundle (package:frontend_server/frontend_server.dart:1126)"}}]
[11:14:16 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"<asynchronous suspension>"}}]
[11:14:16 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"#18     FrontendCompiler.compile (package:frontend_server/frontend_server.dart:904)"}}]
[11:14:16 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"<asynchronous suspension>"}}]
[11:14:16 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"#19     listenAndCompile.<anonymous closure> (package:frontend_server/frontend_server.dart:1701)"}}]
[11:14:16 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"<asynchronous suspension>"}}]
[11:14:16 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"The Dart compiler exited unexpectedly."}}]
[11:14:16 AM] [FlutterWidgetPreview] [Info] <== [{"event":"widget_preview.logMessage","params":{"level":"error","message":"Failed to compile application."}}]

@DanTup

DanTup commented Sep 30, 2026

Copy link
Copy Markdown
Contributor

@bkonyi I re-ran my tests 10 times after your master branch update, and 3/10 failed. All of them were VS Code issues (sidebar not loading correctly), and none were any of the errors above.

This change definitely resolves multiple issues so I think we should land it. If I find any other flakes I'll file separate issues with the details. Thanks!

@bkonyi bkonyi added the autosubmit Merge PR when tree becomes green via auto submit App label Oct 1, 2026
@auto-submit
auto-submit Bot added this pull request to the merge queue Oct 1, 2026
Merged via the queue into flutter:master with commit bcb21e8 Oct 1, 2026
23 checks passed
@flutter-dashboard flutter-dashboard Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Oct 1, 2026
@jtmcdole

jtmcdole commented Oct 1, 2026

Copy link
Copy Markdown
Member

reason for revert: widget preview failures in Windows tool_integration_tests_10_10

08:53 +19 -1: test/integration.shard/widget_preview_detection_test.dart: widget-preview detection Previews within libraries with parts are detected (LSP)
08:53 +19 -1: test/integration.shard/widget_preview_detection_test.dart: widget-preview detection Modified previews are detected (LSP) [E]
  Bad state: Cannot add new events after calling close
  dart:async                                           _BroadcastStreamController.add
  package:flutter_tools/src/dart/analysis.dart 302:30  AnalysisServer._handleProgress
  package:flutter_tools/src/dart/analysis.dart 272:15  AnalysisServer._handleServerResponse
  package:flutter_tools/src/dart/analysis.dart 226:7   AnalysisServer._handleServerResponseRaw
  
  This test failed after it had already completed.
  Make sure to use a matching library which informs the test runner
  of pending async work.
  dart:async                                           _BroadcastStreamController.add
  package:flutter_tools/src/dart/analysis.dart 302:30  AnalysisServer._handleProgress
  package:flutter_tools/src/dart/analysis.dart 272:15  AnalysisServer._handleServerResponse
  package:flutter_tools/src/dart/analysis.dart 226:7   AnalysisServer._handleServerResponseRaw
  
Bad state: Cannot add new events after calling close
#0      _BroadcastStreamController.add (dart:async/broadcast_stream_controller.dart:256:24)
#1      AnalysisServer._handleProgress (package:flutter_tools/src/dart/analysis.dart:304:30)
#2      AnalysisServer._handleServerResponse (package:flutter_tools/src/dart/analysis.dart:272:15)
#3      AnalysisServer._handleServerResponseRaw (package:flutter_tools/src/dart/analysis.dart:226:7)
#4      Zone.runUnaryGuarded (dart:async/zone.dart:486:14)
#5      _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381:11)
#6      _BufferingStreamSubscription._add (dart:async/stream_impl.dart:312:7)
#7      _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:798:19)
#8      _StreamController._add (dart:async/stream_controller.dart:663:7)
#9      _StreamController.add (dart:async/stream_controller.dart:618:5)
#10     _Socket._onData (dart:io-patch/socket_patch.dart:2906:41)
#11     Zone.runUnaryGuarded (dart:async/zone.dart:486:14)
#12     _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:381:11)
#13     _BufferingStreamSubscription._add (dart:async/stream_impl.dart:312:7)
#14     _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:798:19)
#15     _StreamController._add (dart:async/stream_controller.dart:663:7)
#16     _StreamController.add (dart:async/stream_controller.dart:618:5)
#17     new _RawSocket.<anonymous closure> (dart:io-patch/socket_patch.dart:2344:31)
#18     _NativeSocket.issueReadEvent.issue (dart:io-patch/socket_patch.dart:1679:14)
#19     _microtaskLoop (dart:async/schedule_microtask.dart:40:35)
#20     _startMicrotaskLoop (dart:async/schedule_microtask.dart:49:5)
#21     _runPendingImmediateCallback (dart:isolate-patch/isolate_patch.dart:127:13)
#22     _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:5)

  Bad state: Cannot add new events after calling close
  dart:async                                           _BroadcastStreamController.add
  package:flutter_tools/src/dart/analysis.dart 304:30  AnalysisServer._handleProgress
  package:flutter_tools/src/dart/analysis.dart 272:15  AnalysisServer._handleServerResponse
  package:flutter_tools/src/dart/analysis.dart 226:7   AnalysisServer._handleServerResponseRaw

@jtmcdole jtmcdole added revert_wf Revert using Github Workflow revert Autorevert PR (with "Reason for revert:" comment) labels Oct 1, 2026
@flutteractionsbot

Copy link
Copy Markdown
Contributor

Successfully created revert PR: #193637

@flutteractionsbot flutteractionsbot removed the revert Autorevert PR (with "Reason for revert:" comment) label Oct 1, 2026
Renzo-Olivares pushed a commit to Renzo-Olivares/flutter that referenced this pull request Oct 1, 2026
… wait for analysis over DTD in widget preview (flutter#193637)

Reverts: [[flutter_tools] Fix DTD "Stream already subscribed" error and
wait for analysis over DTD in widget
preview](flutter#192930)

Initiated by: @jtmcdole

Reason for reverting: ```

Original PR Author: @bkonyi

Reviewed By: @DanTup

The original PR description is provided below:

## Description

During widget preview startup or file updates:
1. Concurrent calls to retrieve previews or wait for analysis (e.g.,
initial command startup racing with file watcher events) could
concurrently invoke `_waitForLspService()`, causing duplicate
`streamListen` calls to the Dart Tooling Daemon. DTD throws JSON-RPC
error 103 (`Stream already subscribed`) when a client attempts to
subscribe to a stream it is already listening to.
2. `WidgetPreviewDtdServices` previously considered the `Lsp` service
ready as soon as *any* `Lsp` method was registered on DTD (or upon
receiving the first `ServiceRegistered` event for `Lsp`). Because the
analysis server registers its LSP methods sequentially before posting an
`initialized` event on the `Lsp` stream, calls to
`Lsp.dart/workspace/analysis/complete` or
`Lsp.dart/workspace/getFlutterWidgetPreviews` could race ahead of their
registration and fail with `-32601 (method not found)`.
3. When connecting to a pre-existing analysis server over DTD
(`--dtd-url`), `LspPreviewDetector.analysisServer` is `null`, causing
`analysisServer?.waitForAnalysis()` calls during startup and file
updates to be no-ops.

This change:
- Deduplicates in-flight calls to `_waitForLspService()` using a shared
future (`_waitForLspServiceFuture`) so concurrent callers await the same
LSP registration check instead of issuing duplicate DTD requests.
- Separates `lspServiceAvailable` (whether an analysis server has begun
registering `Lsp` services on DTD) from `_allLspServicesRegistered`
(whether all required widget preview LSP methods in
`kRequiredLspServices` are registered), and updates
`_waitForLspServiceHelper()` to listen for the `initialized` event on
the `Lsp` stream before checking `getRegisteredServices()`.
- Consolidates LSP DTD calls into `_callLspService()` and removes the
`kMethodNotFound` polling loop now that `_waitForLspService()` ensures
all required LSP methods are registered.
- Safely catches and ignores `RpcErrorCodes.kStreamAlreadySubscribed` on
`streamListen` calls in `WidgetPreviewDtdServices` (`safeStreamListen`).
- Adds `WidgetPreviewDtdServices.waitForAnalysis()` (invoking
`Lsp.dart/workspace/analysis/complete` over DTD), unifies
`LspPreviewDetector.waitForAnalysis()` so widget preview waits for
analysis completion on both tool-managed and pre-existing analysis
servers, and moves the startup `waitForAnalysis()` call inside the DTD
error-handling `try / catch` block in `WidgetPreviewStartCommand`.
- Adds hermetic regression tests covering concurrent/pre-subscribed DTD
streams, partial vs. full LSP service registration (`Lsp.initialized`),
and waiting for analysis over DTD.

Fixes flutter#192424

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [AI contribution guidelines] and understand my
responsibilities, or I am not using AI tools.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant in-code documentation (doc comments with
`///`).
- [x] If this PR introduces a new feature or capability, I created and
linked a website documentation issue or PR in [flutter/website] (or
verified none is needed).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[AI contribution guidelines]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#ai-contribution-guidelines
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[flutter/website]: https://github.com/flutter/website
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
@bkonyi bkonyi removed the t: cp-candidate A PR that should be considered for a cherry-pick upon landing. label Oct 1, 2026
auto-submit Bot pushed a commit to flutter/packages that referenced this pull request Oct 1, 2026
…13104)

Manual roll requested by [email protected]

flutter/flutter@d649d2b...e89fd0a

2026-10-01 [email protected] Manual roll ICU from 6ebb40c59477 to 5aa526207171 (2 revisions) (flutter/flutter#193661)
2026-10-01 [email protected] fix(web): hash source maps before rewriting sourceMappingURL with --web-content-hash (flutter/flutter#193614)
2026-10-01 [email protected] [flutter_tools] Bootstrap DeviceManager in ToolDependencies (flutter/flutter#193524)
2026-10-01 [email protected] [wasm] Set flutter_runtime_mode in tools/gn to_gn_wasm_args (flutter/flutter#193407)
2026-10-01 [email protected] Remove remaining `download_jdk` references (flutter/flutter#193562)
2026-10-01 [email protected] Synchronize dart2wasm feature probes in roll script and flutter_bootstrap.js (flutter/flutter#193271)
2026-10-01 [email protected] [web] Unskip web tests that now pass in gestures, services, and widgets (flutter/flutter#193512)
2026-10-01 [email protected] Roll Fuchsia Test Scripts from whZAV1mfT-Rdc0rQ8... to fCNknap4ZI0AMcvIf... (flutter/flutter#193640)
2026-10-01 [email protected] Roll Skia from 0575a37d0619 to f2d68e0b8863 (2 revisions) (flutter/flutter#193621)
2026-10-01 [email protected] perf(widgets): use const <Never>{} in InheritedModelElement and avoid redundant casts in RenderObjectElement.update (flutter/flutter#192913)
2026-10-01 [email protected] [web] Unskip and strengthen missing glyph tofu test on Wimp (flutter/flutter#193426)
2026-10-01 [email protected] [flutter_tools] Fix `flutter drive -d chrome` hanging on web (flutter/flutter#193459)
2026-10-01 [email protected] [web] Fix hang when Chromium cannot bind remote debugging port (flutter/flutter#193461)
2026-10-01 [email protected] [flutter_tools] Bundle data assets from hooks in flutter test (flutter/flutter#193435)
2026-10-01 [email protected] Roll Packages from 0ba9a82 to d5ec6db (11 revisions) (flutter/flutter#193641)
2026-10-01 [email protected] Revert: [flutter_tools] Fix DTD "Stream already subscribed" error and wait for analysis over DTD in widget preview (flutter/flutter#193637)
2026-10-01 [email protected] Roll Skia from 6182a3cf8f98 to 0575a37d0619 (5 revisions) (flutter/flutter#193613)
2026-10-01 [email protected] [flutter_tools] Fix DTD "Stream already subscribed" error and wait for analysis over DTD in widget preview (flutter/flutter#192930)
2026-09-30 [email protected] [Impeller] Sample the render target rect in offscreen advanced blends (flutter/flutter#192988)
2026-09-30 [email protected] Roll Skia from 01524014dff5 to 6182a3cf8f98 (11 revisions) (flutter/flutter#193594)
2026-09-30 [email protected] [web] Use Xvfb -displayfd and clean up Xvfb after Firefox test suites (flutter/flutter#193510)
2026-09-30 [email protected] Fixes bug where sibling node fail to update size (flutter/flutter#191220)
2026-09-30 [email protected] Roll Skia from c7b323126bf0 to 01524014dff5 (3 revisions) (flutter/flutter#193577)
2026-09-30 [email protected] Remove some Undefined Behavior from run_customer_testing_tests.dart. (flutter/flutter#193582)
2026-09-30 [email protected] Fix pointer id/coordinate mismatch in Android platform view multi-touch (flutter/flutter#191631)
2026-09-30 [email protected] Roll Packages from 3c6ce59 to 0ba9a82 (11 revisions) (flutter/flutter#193578)
2026-09-30 [email protected] Fix unresolved doc comment references in dev/ tooling (flutter/flutter#193501)

If this roll has caused a breakage, revert this CL and set the roller
to dry run mode using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC [email protected],[email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
bkonyi added a commit to bkonyi/flutter that referenced this pull request Oct 2, 2026
… wait for analysis over DTD in widget preview" (flutter#193658)

## Description

Relands flutter#192930 (which was
reverted in flutter#193637).

### What changed since the original PR
- In `AnalysisServer`, store and cancel the `stdout` and `stderr` stream
subscriptions in `dispose()` before closing `_analyzingController` and
`_errorsController`, and guard `_analyzingController.add` with
`!_analyzingController.isClosed` in `_handleProgress`. Previously,
`$/progress` notifications arriving from the language server during or
after `AnalysisServer.dispose()` threw `Bad state: Cannot add new events
after calling close` in `widget_preview_scaffold_test.dart`.
- In `widget_preview_test_helpers.dart`, await `analysisServer.onExit`
after `analysisServer.dispose()` in `addTearDown` so the analysis server
process has fully exited before temporary directory cleanup on Windows.
- Added a hermetic unit test in `analyze_continuously_test.dart`
verifying that `AnalysisServer` does not throw when `$/progress`
notifications arrive during or after `dispose()`.

### Original description
During widget preview startup or file updates:
1. Concurrent calls to retrieve previews or wait for analysis (e.g.,
initial command startup racing with file watcher events) could
concurrently invoke `_waitForLspService()`, causing duplicate
`streamListen` calls to the Dart Tooling Daemon. DTD throws JSON-RPC
error 103 (`Stream already subscribed`) when a client attempts to
subscribe to a stream it is already listening to.
2. `WidgetPreviewDtdServices` previously considered the `Lsp` service
ready as soon as *any* `Lsp` method was registered on DTD (or upon
receiving the first `ServiceRegistered` event for `Lsp`). Because the
analysis server registers its LSP methods sequentially before posting an
`initialized` event on the `Lsp` stream, calls to
`Lsp.dart/workspace/analysis/complete` or
`Lsp.dart/workspace/getFlutterWidgetPreviews` could race ahead of their
registration and fail with `-32601 (method not found)`.
3. When connecting to a pre-existing analysis server over DTD
(`--dtd-url`), `LspPreviewDetector.analysisServer` is `null`, causing
`analysisServer?.waitForAnalysis()` calls during startup and file
updates to be no-ops.

This change:
- Deduplicates in-flight calls to `_waitForLspService()` using a shared
future (`_waitForLspServiceFuture`) so concurrent callers await the same
LSP registration check instead of issuing duplicate DTD requests.
- Separates `lspServiceAvailable` (whether an analysis server has begun
registering `Lsp` services on DTD) from `_allLspServicesRegistered`
(whether all required widget preview LSP methods in
`kRequiredLspServices` are registered), and updates
`_waitForLspServiceHelper()` to listen for the `initialized` event on
the `Lsp` stream before checking `getRegisteredServices()`.
- Consolidates LSP DTD calls into `_callLspService()` and removes the
`kMethodNotFound` polling loop now that `_waitForLspService()` ensures
all required LSP methods are registered.
- Safely catches and ignores `RpcErrorCodes.kStreamAlreadySubscribed` on
`streamListen` calls in `WidgetPreviewDtdServices` (`safeStreamListen`).
- Adds `WidgetPreviewDtdServices.waitForAnalysis()` (invoking
`Lsp.dart/workspace/analysis/complete` over DTD), unifies
`LspPreviewDetector.waitForAnalysis()` so widget preview waits for
analysis completion on both tool-managed and pre-existing analysis
servers, and moves the startup `waitForAnalysis()` call inside the DTD
error-handling `try / catch` block in `WidgetPreviewStartCommand`.
- Adds hermetic regression tests covering concurrent/pre-subscribed DTD
streams, partial vs. full LSP service registration (`Lsp.initialized`),
and waiting for analysis over DTD.

Fixes flutter#192424

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [AI contribution guidelines] and understand my
responsibilities, or I am not using AI tools.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant in-code documentation (doc comments with
`///`).
- [x] If this PR introduces a new feature or capability, I created and
linked a website documentation issue or PR in [flutter/website] (or
verified none is needed).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[AI contribution guidelines]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#ai-contribution-guidelines
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[flutter/website]: https://github.com/flutter/website
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CICD Run CI/CD revert_wf Revert using Github Workflow tool Affects the "flutter" command-line tool. See also t: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

"Stream already subscribed" in Flutter Widget preview

5 participants