Is there an existing issue for this?
Which plugins are affected?
Other
Which platforms are affected?
Web
Description
In Flutter Web applications, when utilizing JS-Interop SDKs (such as Firebase Data Connect, WebSockets, or third-party JS listeners) that maintain active event subscriptions in the browser, triggering a Hot Restart causes type check failures.
Specifically, the browser's JavaScript environment persists across Hot Restarts while the Dart VM restarts. Lingering JS callbacks continue firing and passing events back into the newly loaded Dart context. When the new Dart runtime performs a type-check on elements returned from these callbacks, it fails with:
TypeError: Instance of 'LegacyJavaScriptObject': type 'LegacyJavaScriptObject' is not a subtype of type 'MyClass'
This is caused by the type representation changing between VM reloads, causing Dart to treat the old execution's objects as generic JS objects (LegacyJavaScriptObject).
Reproducing the issue
- Configure Firebase Data Connect in a Flutter Web project.
- Define a GraphQL query (e.g., ListMessages) and generate the SDK.
- Call subscribe().listen((result) { ... }) on the generated query reference.
- Perform a Hot Restart (r in the terminal or click hot restart in your IDE).
- As soon as the page loads and registers the query subscription, it immediately receives the initial/cached query data.
- The app crashes immediately with the following type-cast error during the mapping phase
Firebase Core version
4.9.0
Flutter Version
3.41.8
Relevant Log Output
Flutter dependencies
Expand Flutter dependencies snippet
Replace this line with the contents of your `flutter pub deps -- --style=compact`.
Additional context and comments
Workaround
To bypass this during development, detect if the application is starting up from a hot-restart state on the web. If a global flag is already present in window, programmatically force a browser refresh (window.location.reload()) to cleanly flush the JS environment:
import 'dart:js_interop';
import 'package:flutter/foundation.dart';
@JS('window')
external JSObject get _window;
@JS('window.location.reload')
external void _reloadPage();
@JS('Reflect.has')
external bool _reflectHas(JSObject target, JSString propertyKey);
@JS('Reflect.set')
external bool _reflectSet(JSObject target, JSString propertyKey, JSAny value);
void checkHotRestart() {
if (kIsWeb && kDebugMode) {
try {
final windowObj = _window;
final hasLoaded = _reflectHas(windowObj, '__hasLoaded'.toJS);
if (hasLoaded) {
_reloadPage();
return;
}
_reflectSet(windowObj, '__hasLoaded'.toJS, true.toJS);
} catch (_) {}
}
}
Workaround Caveats
Web Debugger Connection Warning: Forcing a browser reload outside of the Dart debugger's flow interrupts the active Debugger Connection (DWDS), printing these harmless warnings to the terminal:
AppInspector: Error calling Runtime.evaluate with params {expression: ...} Error: WipError -32000 Cannot find context with specified id
RemoteDebuggerExecutionContext: Timed out finding an execution context after 100 ms.
The debugger automatically re-attaches once the browser finishes reloading.
Is there an existing issue for this?
Which plugins are affected?
Other
Which platforms are affected?
Web
Description
In Flutter Web applications, when utilizing JS-Interop SDKs (such as Firebase Data Connect, WebSockets, or third-party JS listeners) that maintain active event subscriptions in the browser, triggering a Hot Restart causes type check failures.
Specifically, the browser's JavaScript environment persists across Hot Restarts while the Dart VM restarts. Lingering JS callbacks continue firing and passing events back into the newly loaded Dart context. When the new Dart runtime performs a type-check on elements returned from these callbacks, it fails with:
TypeError: Instance of 'LegacyJavaScriptObject': type 'LegacyJavaScriptObject' is not a subtype of type 'MyClass'This is caused by the type representation changing between VM reloads, causing Dart to treat the old execution's objects as generic JS objects (LegacyJavaScriptObject).
Reproducing the issue
Firebase Core version
4.9.0
Flutter Version
3.41.8
Relevant Log Output
Flutter dependencies
Expand
Flutter dependenciessnippetReplace this line with the contents of your `flutter pub deps -- --style=compact`.Additional context and comments
Workaround
To bypass this during development, detect if the application is starting up from a hot-restart state on the web. If a global flag is already present in window, programmatically force a browser refresh (window.location.reload()) to cleanly flush the JS environment:
Workaround Caveats
Web Debugger Connection Warning: Forcing a browser reload outside of the Dart debugger's flow interrupts the active Debugger Connection (DWDS), printing these harmless warnings to the terminal:
The debugger automatically re-attaches once the browser finishes reloading.