Skip to content

Web WASM: "RuntimeError: illegal cast at DriftCommunication._handleMessage" #3113

Description

@OlegShNayax

Steps to reproduce

  1. Clone repository https://github.com/OlegShNayax/drift_wasm_example
  2. Build project using flutter build web --wasm --no-strip-wasm
  3. Run project using dhttpd '--headers=Cross-Origin-Embedder-Policy=credentialless;Cross-Origin-Opener-Policy=same-origin' --path=build/web --port=8085
  4. Open project in Chrome http://localhost:8085/
  5. Open console Developer Tools > Console

Expected results

We see log "initialize drift database" end everything works fine.

Actual results

We see log "initialize drift database" and error:

main.dart.wasm:0x149921 Uncaught 
RuntimeError: illegal cast
    at DriftCommunication._handleMessage (main.dart.wasm:0x149921)
    at DriftCommunication._handleMessage tear-off trampoline (main.dart.wasm:0x149b3c)
    at _RootZone.runUnaryGuarded (main.dart.wasm:0xd475e)
    at _BufferingStreamSubscription._sendData (main.dart.wasm:0xd87a6)
    at _BufferingStreamSubscription._add (main.dart.wasm:0xd8974)
    at _SyncStreamController._sendData (main.dart.wasm:0x14fe16)
    at _StreamController._add (main.dart.wasm:0x146cc2)
    at _StreamController.add (main.dart.wasm:0x146c76)
    at _StreamController.add tear-off trampoline (main.dart.wasm:0x150957)
    at _RootZone.runUnaryGuarded (main.dart.wasm:0xd475e)

Code sample

Code sample

main.dart

import 'package:drift_wasm_example/database/dao/drift_actor_dao.dart';
import 'package:drift_wasm_example/database/drift_database.dart';
import 'package:drift_wasm_example/database/entities/drift_actor_entity.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  late final DriftDatabaseImpl _database;
  late final DriftActorDao _actorDao;

  @override
  void initState() {
    super.initState();
    _initializeDatabase();
  }

  Future<void> _initializeDatabase() async {
    print("initialize drift database");
    _database = DriftDatabaseImpl();
    _actorDao = _database.driftActorDao;
  }

  Future<void> _insertActors() async {
    final generatedActors = List.generate(
      100,
      (index) => DriftActorEntity(
        actorID: "$index",
        parentActorID: "$index",
        actorDescription: "Actor #$index description",
        actorDistributorId: "$index",
        actorTypeID: index,
        actorStatus: index,
        actorMachinesCount: index * 10,
      ),
    );

    await _actorDao.insertActors(generatedActors);
  }

  Future<void> _printActors() async {
    final savedActors = await _actorDao.getActors();
    for(final actor in savedActors) {
      print(actor);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      persistentFooterButtons: [
        FloatingActionButton(
          onPressed: _insertActors,
          tooltip: 'Insert 100 actors',
          child: const Icon(Icons.add),
        ),
        const SizedBox(width: 20.0),
        FloatingActionButton(
          onPressed: _printActors,
          tooltip: 'Print actors',
          child: const Icon(Icons.print),
        ),
      ], // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

drift_database.dart

DatabaseConnection connectOnWeb() {
  return DatabaseConnection.delayed(Future(() async {
    final result = await WasmDatabase.open(
      databaseName: 'my_app_db', // prefer to only use valid identifiers here
      sqlite3Uri: Uri.parse('sqlite3.wasm'),
      driftWorkerUri: Uri.parse('drift_worker.js'),
    );

    if (result.missingFeatures.isNotEmpty) {
      // Depending how central local persistence is to your app, you may want
      // to show a warning to the user if only unrealiable implemetentations
      // are available.
      print('Using ${result.chosenImplementation} due to missing browser '
          'features: ${result.missingFeatures}');
    }

    return result.resolvedExecutor;
  }));
}

@DriftDatabase(tables: [
  DriftActorTable,
], daos: [
  DriftActorDao
])
class DriftDatabaseImpl extends _$DriftDatabaseImpl {
  DriftDatabaseImpl._(super.e);

  factory DriftDatabaseImpl() => DriftDatabaseImpl._(connectOnWeb());

  @override
  int get schemaVersion => 1;
}

drift_actor_entity.dart

class DriftActorEntity implements Insertable<DriftActorEntity> {
  String? actorID;
  String? parentActorID;
  String? actorDescription;
  String? actorDistributorId;
  int? actorTypeID;
  int? actorStatus;
  int? actorMachinesCount;

  DriftActorEntity(
      {this.parentActorID,
      this.actorID,
      this.actorDescription,
      this.actorDistributorId,
      this.actorTypeID,
      this.actorStatus,
      this.actorMachinesCount});

  @override
  Map<String, Expression> toColumns(bool nullToAbsent) {
    return DriftActorTableCompanion(
      actorID: Value(actorID),
      parentActorID: Value(parentActorID),
      actorDescription: Value(actorDescription),
      actorDistributorId: Value(actorDistributorId),
      actorTypeID: Value(actorTypeID),
      actorStatus: Value(actorStatus),
      actorMachinesCount: Value(actorMachinesCount),
    ).toColumns(nullToAbsent);
  }

  @override
  String toString() {
    return 'DriftActorEntity{actorID: $actorID, parentActorID: $parentActorID, actorDescription: $actorDescription, actorDistributorId: $actorDistributorId, actorTypeID: $actorTypeID, actorStatus: $actorStatus, actorMachinesCount: $actorMachinesCount}';
  }
}

DriftActorTable

@UseRowClass(DriftActorEntity)
class DriftActorTable extends Table {
  @override
  String get tableName => 'actor';

  TextColumn get actorID => text().named("actorID").nullable()();
  TextColumn get parentActorID => text().named("parentActorID").nullable()();
  TextColumn get actorDescription => text().named("actorDescription").nullable()();
  TextColumn get actorDistributorId => text().named("actorDistributorId").nullable()();
  IntColumn get actorTypeID => integer().named("actorTypeID").nullable()();
  IntColumn get actorStatus => integer().named("actorStatus").nullable()();
  IntColumn get actorMachinesCount => integer().named("actorMachinesCount").nullable()();

  @override
  Set<Column>? get primaryKey => {actorID};
}

DriftActorDao

@DriftAccessor(tables: [DriftActorTable])
class DriftActorDao extends DatabaseAccessor<DriftDatabaseImpl>
    with _$DriftActorDaoMixin {
  DriftActorDao(DriftDatabaseImpl db) : super(db);

  @override
  Future<void> insertActors(List<DriftActorEntity> actors) {
    return batch((batch) {
      batch.insertAll(driftActorTable, actors,
          mode: InsertMode.insertOrReplace);
    });
  }

  @override
  Future<List<DriftActorEntity>> getActors() {
    return (select(driftActorTable)).get();
  }
}

Flutter Doctor output

Flutter Doctor output
% flutter doctor -v
[✓] Flutter (Channel stable, 3.22.3, on macOS 13.6.7 22G720 darwin-x64, locale en-IL)
    • Flutter version 3.22.3 on channel stable at /Users/olegs/Documents/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision b0850beeb2 (8 days ago), 2024-07-16 21:43:41 -0700
    • Engine revision 235db911ba
    • Dart version 3.4.4
    • DevTools version 2.34.3

[✓] Android toolchain - develop for Android devices (Android SDK version 31.0.0-rc5)
    • Android SDK at /Users/olegs/Library/Android/sdk
    • Platform android-34, build-tools 31.0.0-rc5
    • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b829.9-10027231)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 15.0)
    • Xcode at /Users/olegs/Downloads/Xcode.app/Contents/Developer
    • Build 15A240d
    • CocoaPods version 1.15.2

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2022.3)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b829.9-10027231)

[✓] VS Code (version 1.58.2)
    • VS Code at /Users/olegs/Downloads/Visual Studio Code.app/Contents
    • Flutter extension can be installed from:
      🔨 https://marketplace.visualstudio.com/items?itemName=Dart-Code.flutter

[✓] VS Code (version 1.91.1)
    • VS Code at /Applications/Visual Studio Code 2.app/Contents
    • Flutter extension can be installed from:
      🔨 https://marketplace.visualstudio.com/items?itemName=Dart-Code.flutter

[✓] Connected device (2 available)           
    • macOS (desktop) • macos  • darwin-x64     • macOS 13.6.7 22G720 darwin-x64
    • Chrome (web)    • chrome • web-javascript • Google Chrome 126.0.6478.183

[✓] Network resources
    • All expected network resources are available.

I think there is issue with drift_worker.js

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions