Newly Uploaded Images to Supabase Storage Not Displaying Immediately - Status 400 Error

100 views Asked by At

I’m encountering an issue when uploading images to Supabase storage. After uploading the images and updating the database with the new photo URLs, I attempt to display them immediately. However, I receive a status 400 error (GET method). Interestingly, the URLs work when checked separately, and images uploaded earlier are displayed properly. The issue only arises with newly uploaded photos.

Here is my code for context:

    const handleFormSubmit = async (
        values: Artist,
        setSubmitting: SetSubmitting
    ) => {
        setSubmitting(true)

        // Filter images to don't upload images that are going to be deleted and vice versa
        const {
            itemsToUploadClone: imagesToUploadClone,
            itemsToDeleteClone: imagesToDeleteClone,
        } = filterItems(imagesToUpload, imagesToDelete)

        try {
            // Perform image upload and deletion in parallel
            await Promise.all([
                imagesToUploadClone.length > 0
                    ? uploadImages(imagesToUploadClone, values.imgList)
                    : Promise.resolve(),
                imagesToDeleteClone.length > 0
                    ? deleteArtistImages(imagesToDeleteClone)
                    : Promise.resolve(),
            ])

            const success = await apiUpdateArtist(values)

            if (success) {
                navigate('/artists/details/' + values.id)
                popNotification(t('artists.artistUpdated'))
            }
        } catch (error) {
            console.error(
                'Error in processing images or updating artist: ',
                error
            )
        } finally {
            setSubmitting(false)
        }
    }

Here is the code with image transformations and upload to supabase:

    const uploadImages = async (
        imagesToUpload: Image[],
        formImages: Image[]
    ) => {
        await Promise.all(
            imagesToUpload.map(async (imageToUpload) => {
                try {
                    const formImage = formImages.find(
                        (img) => img.id === imageToUpload.id
                    ) as Image

                    const rawFile = await getFileFromBlobUrl(
                        imageToUpload.rawFilePath,
                        imageToUpload.fileName
                    )

                    // resize image to 3 different sizes and upload them to supabase storage

                    const resizeOptions: ResizeOption[] = [
                        {
                            maxWidth: 144,
                            maxHeight: 144,
                            format: 'WEBP',
                            quality: 75,
                            minWidth: 144,
                            minHeight: 144,
                        },
                        {
                            maxWidth: 760,
                            maxHeight: 760,
                            format: 'JPEG',
                            quality: 90,
                            minWidth: 480,
                            minHeight: 480,
                        },
                        {
                            maxWidth: 2000,
                            maxHeight: 2000,
                            format: 'JPEG',
                            quality: 90,
                        },
                    ]

                    try {
                        const resizePromises = resizeFile(
                            rawFile,
                            resizeOptions
                        )
                        let resizedImages = await Promise.all(resizePromises)
                        resizedImages = [...resizedImages, rawFile]

                        const sizes = [
                            'small',
                            'medium',
                            'large',
                            'raw',
                        ] as const

                        resizedImages.forEach(async (resizedImage, index) => {
                            const filePath = `/img/artist/${artistData.id}/${
                                sizes[index]
                            }/${imageToUpload.id}.${resizedImage.type
                                .split('/')[1]
                                .toLowerCase()}`

                            await supabase.storage.from('general').upload(filePath, resizedImage)
                        })

                        const imageBaseUrl = `${
                            import.meta.env.VITE_SUPABASE_STORAGE_URL
                        }/img/artist/${artistData.id}`

                        formImage.smallFilePath = `${imageBaseUrl}/small/${
                            imageToUpload.id
                        }.${resizedImages[0].type.split('/')[1]}`

                        formImage.mediumFilePath = `${imageBaseUrl}/medium/${
                            imageToUpload.id
                        }.${resizedImages[1].type.split('/')[1]}`

                        formImage.largeFilePath = `${imageBaseUrl}/large/${
                            imageToUpload.id
                        }.${resizedImages[2].type.split('/')[1]}`

                        formImage.rawFilePath = `${imageBaseUrl}/raw/${
                            imageToUpload.id
                        }.${resizedImages[3].type.split('/')[1]}`
                    } catch (error) {
                        console.error('Error resizing images:', error)
                    }
                } catch (error) {
                    console.error('Error uploading image: ', error)
                }
            })
        )
    }

The following code refers to the request for an image from the storage (image url):

    {imgList.map((img) => (
                    <SortableItem key={img.id} id={img.id}>
                        <div
                            key={img.id}
                            className="group relative rounded border p-2 flex justify-center touch-pan-x aspect-square"
                        >
                            <img
                                className="rounded object-contain"
                                src={img.smallFilePath}
                                alt={img.fileName}
                            />
                            <div className="absolute inset-2 bg-gray-900/[.7] group-hover:flex hidden text-xl items-center justify-center">
                                <span
                                    className="text-gray-100 hover:text-gray-300 cursor-pointer p-1.5"
                                    onClick={() => onViewOpen(img)}
                                >
                                    <HiEye />
                                </span>
                                <span
                                    className="text-gray-100 hover:text-gray-300 cursor-pointer p-1.5"
                                    onClick={() => onDeleteConfirmation(img)}
                                >
                                    <HiTrash />
                                </span>
                            </div>
                        </div>
                    </SortableItem>
                ))}

Here are also the request header screenshots (same image, but one after refreshing the page):
status 400 status 200

To troubleshoot, I added a 1-second timeout before displaying the site with images, which resulted in all images being displayed properly. Additionally, if I initially receive an error and then refresh the page, the images display as expected. I’ve also tried implementing a custom function that checks image availability in an interval loop, but I believe there should be a more appropriate solution. I expected the images to display immediately after uploading without the need for these workarounds.

0

There are 0 answers