flutterflutter-webflutter-imageappwriteflutter-image-picker

"On web `bytes` is required" exception thrown by image_picker plugin on Flutter web


My app is using the image_picker plugin to let the user upload a profile picture from his phone and on Android everything works as expected.

The problem is that when I try to run the same code on web, it throws me the following error:

Error: AppwriteException: null, On web `bytes` is required (0)
    at Object.throw_ [as throw] (http://localhost:42231/dart_sdk.js:5080:11)
    at new input_file.InputFile.new (http://localhost:42231/packages/appwrite/src/input_file.dart.lib.js:79:17)
    at database.DatabaseService.new.uploadProfilePic (http://localhost:42231/packages/presents/services/database.dart.lib.js:299:104)
    at uploadProfilePic.next (<anonymous>)
    at runBody (http://localhost:42231/dart_sdk.js:40660:34)
    at Object._async [as async] (http://localhost:42231/dart_sdk.js:40691:7)
    at database.DatabaseService.new.uploadProfilePic (http://localhost:42231/packages/presents/services/database.dart.lib.js:297:20)
    at http://localhost:42231/packages/presents/screens/profile/show_profilepic_menu.dart.lib.js:262:33
    at Generator.next (<anonymous>)
    at http://localhost:42231/dart_sdk.js:40641:33
    at _RootZone.runUnary (http://localhost:42231/dart_sdk.js:40511:59)
    at _FutureListener.thenAwait.handleValue (http://localhost:42231/dart_sdk.js:35438:29)
    at handleValueCallback (http://localhost:42231/dart_sdk.js:35999:49)
    at Function._propagateToListeners (http://localhost:42231/dart_sdk.js:36037:17)
    at _Future.new.[_completeWithValue] (http://localhost:42231/dart_sdk.js:35872:23)
    at async._AsyncCallbackEntry.new.callback (http://localhost:42231/dart_sdk.js:35906:35)
    at Object._microtaskLoop (http://localhost:42231/dart_sdk.js:40778:13)
    at _startMicrotaskLoop (http://localhost:42231/dart_sdk.js:40784:13)
    at http://localhost:42231/dart_sdk.js:36261:9

I don't know if the problem is with the image_picker plugin or with AppWrite (the backend server), but since when I run the code in Debug mode it stops in the image_picker_for_web.dart file I'd guess the problem is with the former.

Actually, it stops on line 274 where it returns an XFile without the bytes parameter (see the code below), so maybe this is the problem? How can I fix that?

(the code of image_picker_for_web.dart I was talking about, from line 273)

if (!_completer.isCompleted && files != null) {
        _completer.complete(files.map((html.File file) {
          return XFile(
            html.Url.createObjectUrl(file),
            name: file.name,
            length: file.size,
            lastModified: DateTime.fromMillisecondsSinceEpoch(
              file.lastModified ?? DateTime.now().millisecondsSinceEpoch,
            ),
            mimeType: file.type,
          );
        }).toList());
      }

Solution

  • Ok, after some further debugging I found out the problem was not with the image_picker package but with uploading the picked image on AppWrite storage.

    Initially, I was uploading it with a code like this one:

    Future<void> uploadProfilePic(XFlie file) async {
      File res = await _storage.createFile(
        bucketId: Constants.profilePicsBucketID,
        fileId: 'unique()',
        file: InputFile(
          path: file.path,
          filename: '$_uid.${file.path.split('.').last}',
        ),
        read: ['role:all'],
      );
    }
    

    And then I solved my problem passing the createFile function also a bytes parameter. So my final code is:

    Future<void> uploadProfilePic(XFlie file) async {
      List<int> fileBytes = await file.readAsBytes();
    
      File res = await _storage.createFile(
        bucketId: Constants.profilePicsBucketID,
        fileId: 'unique()',
        file: InputFile(
          path: file.path,
          bytes: fileBytes,
          filename: '$_uid.${file.path.split('.').last}',
        ),
        read: ['role:all'],
      );
    }