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

1

8

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();
  }
}

Shirleneshirley answered 19/1, 2022 at 2:1 Comment(0)
M
10

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.

Mccoy answered 19/1, 2022 at 2:27 Comment(3)
@mmcdoc20, thank you!Shirleneshirley
@Mccoy so how do you fix this in the code?Cabinet
Make _processWorkItemsInBackground a top level function instead of a method on the Infrastructure class.Mccoy

© 2022 - 2024 — McMap. All rights reserved.