Search code examples
dartspawndart-isolates

Invalid argument(s): Illegal argument in isolate message: (object is aReceivePort)


I am not sure if I am doing anything wrong in this code but I am clearly passing a SendPort when spawning a new isolate, however when I call: Infrastructure.instance.initialize(); I get following exception:

Invalid argument(s): Illegal argument in isolate message: (object is aReceivePort)

Here is the basic implementation of Infrastructure:

class Infrastructure {
  late final SendPort _sendPort;
  late final ReceivePort _receivePort; 

  Infrastructure._() {
    _receivePort = ReceivePort();
    Isolate.spawn(_processWorkItemsInBackground, _receivePort.sendPort,
        debugName: 'InfrastructureIsolate');

    _sendPort = _receivePort.first as SendPort;
  }

  Future<void> dispose() async {
    // Send a signal to the spawned isolate indicating that it should exit:
    _sendPort.send(null);
  }

  static final Infrastructure instance = Infrastructure._();

  void initialize() {}

  Future<void> _processWorkItemsInBackground(SendPort sendPort) async {
    ModuleLogger.moduleLogger.info('Infrastructure isolate started.');

    // Send a SendPort to the main isolate
    // so that it can send JSON strings to this isolate:
    final commandPort = ReceivePort();
    sendPort.send(commandPort.sendPort);

    // Wait for messages from the main isolate.
    await for (final message in commandPort) {
      // cast the message to one of the expected message types,
      // handle it properly, compile a response and send it back via
      // the sendPort if needed.
      // For example,
      if (message is String) {
        // Read and decode the file.
        final contents = await File(message).readAsString();

        // Send the result to the main isolate.
        sendPort.send(jsonDecode(contents));
      } else if (message == null) {
        // Exit if the main isolate sends a null message, indicating there are no
        // more files to read and parse.
        break;
      }
    }

    ModuleLogger.moduleLogger.info('Infrastructure isolate finished.');
    Isolate.exit();
  }
}


Solution

  • I actually opened a ticket for a similar issue about a month ago:

    https://github.com/dart-lang/sdk/issues/47981

    Turns out there was already a ticket for it here:

    https://github.com/dart-lang/sdk/issues/36983

    I believe what is happening here is that because _processWorkItemsInBackground is not a top level function, it is closing over all of the variables that are in scope, that would include this declaration late final ReceivePort _receivePort;. And so when you spawn the isolate with _processWorkItemsInBackground it is implicitly attempting to send to the isolate everything in scope, but ReceivePorts are not allowed to be sent to an isolate, thus causing the error.