androidXP
androidXP

Reputation: 1719

Firebase E/StorageException: StorageException has occurred. Object does not exist at location

I am trying to upload 4 different images to firebase storage, my code works with a single image, but whenever I try to upload multiple images I get

 E/StorageException: StorageException has occurred.
    Object does not exist at location.
     Code: -13010 HttpResult: 404
2021-11-18 22:45:16.584 com.example.test E/StorageException: {  "error": {    "code": 404,    "message": "Not Found."  }}
    java.io.IOException: {  "error": {    "code": 404,    "message": "Not Found."  }}
        at com.google.firebase.storage.network.NetworkRequest.parseResponse(NetworkRequest.java:445)
        at com.google.firebase.storage.network.NetworkRequest.parseErrorResponse(NetworkRequest.java:462)
        at com.google.firebase.storage.network.NetworkRequest.processResponseStream(NetworkRequest.java:453)
        at com.google.firebase.storage.network.NetworkRequest.performRequest(NetworkRequest.java:272)
        at com.google.firebase.storage.network.NetworkRequest.performRequest(NetworkRequest.java:289)
        at com.google.firebase.storage.internal.ExponentialBackoffSender.sendWithExponentialBackoff(ExponentialBackoffSender.java:76)
        at com.google.firebase.storage.internal.ExponentialBackoffSender.sendWithExponentialBackoff(ExponentialBackoffSender.java:68)
        at com.google.firebase.storage.GetDownloadUrlTask.run(GetDownloadUrlTask.java:77)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:923)

This is my code to upload images to firebase storage and even after getting errors, I can see the images on firebase Storage but I am getting the error on the app.

private synchronized void UploadToFireBaseStorage(ArrayList<String> filePath,int type) {
        
        final ArrayList<String> multipleImages = new ArrayList<>();
        Log.d(TAG,"Size of File at Upload Method "+filePath.size());

        if (filePath.size()==0){
            return;
        }

        
        Uri fileUri = null;

        for (String s : filePath) {
            if (s.contains(".jpg")) {
                    fileUri = Uri.fromFile(new File(s));
                } else {
                    fileUri = Uri.parse(s);
                }

            
            StorageReference mStorageReference = FirebaseStorage.getInstance().getReference();
            Log.d(TAG, "UploadToFireBaseStorage: StorageRef "+mStorageReference);

           
            storageReference = mStorageReference.child("Photos").child(fileUri.getLastPathSegment());
           
            Log.d(TAG, "UploadToFireBaseStorage: Storage Reference "+storageReference);
            Log.d(TAG, "UploadToFireBaseStorage: File URI = "+fileUri);
            String finalAttachmentType = attachmentType;
            String finalUploadFolder = uploadFolder;
            storageReference.putFile(fileUri).addOnSuccessListener(this, new OnSuccessListener<UploadTask.TaskSnapshot>() {
                @Override
                public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {

                    storageReference.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
                        @Override
                        public void onSuccess(@NonNull Uri uri) {
                            Log.d(TAG, "Image Uploaded ");
                            Log.d(TAG, "onSuccess: URI Uploaded == "+uri);
                            
                        }
                    });
                }
            }).addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() {
                @Override
                public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
                    double progress = 100.0 * taskSnapshot.getBytesTransferred() / (double) taskSnapshot.getTotalByteCount();
                    Log.d(TAG, "Upload is " + progress + "% done");
                    

                }
            }).addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception e) {
                    Log.d(TAG, "onFailure: "+s);
                    
                }
            });
        }
        Log.d(TAG,"Image List "+multipleImages.toString());
    }

These are the storage reference i got for 4 different images

Storage Reference gs://example-89902.appspot.com/Photos/Image%20IMG_1637256617899.jpg

Storage Reference gs://example-89902.appspot.com/Photos/Image%20IMG_1637256617949.jpg

Storage Reference gs://example-89902.appspot.com/Photos/Image%20IMG_1637256618132.jpg

Storage Reference gs://example-89902.appspot.com/Photos/Image%20IMG_1637256618070.jpg

Firebase Storage Rules:

Firebase Storage Rules
service firebase.storage {
  match /b/bucket/o {
    match /{allPaths=**} {
      allow read, write;
    }
  }
}

Upvotes: 4

Views: 931

Answers (1)

jccampanero
jccampanero

Reputation: 53381

According to the stack trace the problem seems to be related to obtaining the download url:

at com.google.firebase.storage.GetDownloadUrlTask.run(GetDownloadUrlTask.java:77)

It's probably caused by this code fragment:

@Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {

  storageReference.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
      @Override
      public void onSuccess(@NonNull Uri uri) {
          Log.d(TAG, "Image Uploaded ");
          Log.d(TAG, "onSuccess: URI Uploaded == "+uri);
          
      }
  });
  
}

My guess is that there is some kind of race condition between the upload success callback and the instant in which the storage reference and the corresponding download url are available.

As suggested in the Firebase documentation, please, try modifying your code like this in order to obtain the download url:

private synchronized void UploadToFireBaseStorage(ArrayList<String> filePath,int type) {
        
    final ArrayList<String> multipleImages = new ArrayList<>();
    Log.d(TAG,"Size of File at Upload Method "+filePath.size());

    if (filePath.size()==0){
        return;
    }

    
    Uri fileUri = null;

    for (String s : filePath) {
        if (s.contains(".jpg")) {
                fileUri = Uri.fromFile(new File(s));
            } else {
                fileUri = Uri.parse(s);
            }

        
        StorageReference mStorageReference = FirebaseStorage.getInstance().getReference();
        Log.d(TAG, "UploadToFireBaseStorage: StorageRef "+mStorageReference);

        
        storageReference = mStorageReference.child("Photos").child(fileUri.getLastPathSegment());
        
        Log.d(TAG, "UploadToFireBaseStorage: Storage Reference "+storageReference);
        Log.d(TAG, "UploadToFireBaseStorage: File URI = "+fileUri);
        String finalAttachmentType = attachmentType;
        String finalUploadFolder = uploadFolder;
        UploadTask uploadTask = storageReference.putFile(fileUri).addOnSuccessListener(this, new OnSuccessListener<UploadTask.TaskSnapshot>() {
            @Override
            public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
                // The stuff you considerd appropriate
                Log.d(TAG, "Image Uploaded ");
            }
        }).addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() {
            @Override
            public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
                double progress = 100.0 * taskSnapshot.getBytesTransferred() / (double) taskSnapshot.getTotalByteCount();
                Log.d(TAG, "Upload is " + progress + "% done");
                

            }
        }).addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                Log.d(TAG, "onFailure: "+s);
                
            }
        });

        uploadTask.continueWithTask(new Continuation<UploadTask.TaskSnapshot, Task<Uri>>() {
            @Override
            public Task<Uri> then(@NonNull Task<UploadTask.TaskSnapshot> task) throws Exception {
                if (!task.isSuccessful()) {
                    throw task.getException();
                }

                // Continue with the task to get the download URL
                return ref.getDownloadUrl();
            }
        }).addOnCompleteListener(new OnCompleteListener<Uri>() {
            @Override
            public void onComplete(@NonNull Task<Uri> task) {
                if (task.isSuccessful()) {
                    Uri downloadUri = task.getResult();
                    Log.d(TAG, "onSuccess: URI Uploaded == "+downloadUri);
                } else {
                    // Handle failures
                    // ...
                }
            }
        });
    }
    Log.d(TAG,"Image List "+multipleImages.toString());
}

Previously UploadTask.TaskSnapshot had a getDownloadUrl() method, but it is no longer available. The subject has been discussed in different issues like this one, for instance, which provides further alternatives as well.


As a side note, and probably unrelated, but certainly curious, you pointed out in your comments that two of the images are uploaded successfully and two not. As you can see in the source code of Uploadtask, this kind of tasks are scheduled using the following code:

@Override
protected void schedule() {
  StorageTaskScheduler.getInstance().scheduleUpload(getRunnable());
}

StorageTaskScheduler schedules uploads in a thread pool executor of a maximum of two threads:

private static final ThreadPoolExecutor UPLOAD_QUEUE_EXECUTOR =
    new ThreadPoolExecutor(
        2, 2, 5, TimeUnit.SECONDS, mUploadQueue, new StorageThreadFactory("Upload-"));

Maybe some uploads are being blocked by this thread pool as you are trying uploading a greater number of images that the available number of threads.

In contrast, the operation for obtaining the download url is performed in a different thread pool:

private static final ThreadPoolExecutor COMMAND_POOL_EXECUTOR =
    new ThreadPoolExecutor(
        5, 5, 5, TimeUnit.SECONDS, mCommandQueue, new StorageThreadFactory("Command-"));

As you can see, in this pool the number of threads is five and it means there is enough room to submit the get download task operations.

I reviewed the code and cannot find any leak, but it is certain that this difference may be related to your problem in any way.

Upvotes: 1

Related Questions