Platform
Flutter Web (dart2js release build)
SDK version
sentry_flutter 9.14.0 — but the affected code is unchanged in 9.24.0:
https://github.com/getsentry/sentry-dart/blob/9.24.0/packages/flutter/lib/src/web/script_loader/web_script_dom_api.dart
Description
loadScript() wires both listeners straight to the completer with no isCompleted guards:
final completer = Completer<void>();
final script = HTMLScriptElement()
..crossOrigin = 'anonymous'
..onLoad.listen((_) => completer.complete())
..onError.listen((event) => completer.completeError('Failed to load $src'));
onLoad/onError are streams, and browsers can deliver more than one event for the same <script> element — e.g. an error during a flaky mobile connection followed by a later load, or event re-delivery around Safari back/forward-cache restores. The second delivery throws StateError: Bad state: Future already completed inside the DOM event callback, which surfaces as an unhandled fatal event in Sentry itself — the SDK reports its own loader crash.
We see this steadily in production on a public Flutter-web page opened mostly from mobile devices (iOS Safari heavy): 11 events / 9 users over ~10 weeks, level fatal, culprit web_script_dom_api.dart loadScript.<anonymous function>. The page itself is unaffected — it's pure noise, but fatal-level noise that pollutes release health and triggers regression alerts on every release.
Expected
The loader should complete at most once, e.g.:
..onLoad.listen((_) {
if (!completer.isCompleted) completer.complete();
})
..onError.listen((event) {
if (!completer.isCompleted) completer.completeError('Failed to load $src');
});
(or .first-based single-shot subscriptions that cancel the sibling listener).
Steps to reproduce
Hard to reproduce deterministically — it needs a double load/error event delivery on the injected SDK <script>. Consistently observable in aggregate on any high-traffic mobile-web deployment with SentryFlutter.init defaults (JS SDK auto-loading enabled).
🤖 Filed with Claude Code
Platform
Flutter Web (dart2js release build)
SDK version
sentry_flutter 9.14.0 — but the affected code is unchanged in 9.24.0:
https://github.com/getsentry/sentry-dart/blob/9.24.0/packages/flutter/lib/src/web/script_loader/web_script_dom_api.dart
Description
loadScript()wires both listeners straight to the completer with noisCompletedguards:onLoad/onErrorare streams, and browsers can deliver more than one event for the same<script>element — e.g. anerrorduring a flaky mobile connection followed by a laterload, or event re-delivery around Safari back/forward-cache restores. The second delivery throwsStateError: Bad state: Future already completedinside the DOM event callback, which surfaces as an unhandled fatal event in Sentry itself — the SDK reports its own loader crash.We see this steadily in production on a public Flutter-web page opened mostly from mobile devices (iOS Safari heavy): 11 events / 9 users over ~10 weeks, level
fatal, culpritweb_script_dom_api.dartloadScript.<anonymous function>. The page itself is unaffected — it's pure noise, but fatal-level noise that pollutes release health and triggers regression alerts on every release.Expected
The loader should complete at most once, e.g.:
(or
.first-based single-shot subscriptions that cancel the sibling listener).Steps to reproduce
Hard to reproduce deterministically — it needs a double load/error event delivery on the injected SDK
<script>. Consistently observable in aggregate on any high-traffic mobile-web deployment withSentryFlutter.initdefaults (JS SDK auto-loading enabled).🤖 Filed with Claude Code