Can't upload images to RETOOL STORAGE

Getting an error when trying to upload an image into Retool Storage. The error states "Cannot read property EndsWith of undefined. This was working fine just yesterday, and I am seeing the error today and noticing other retool users reporting it as well. My end users can't see the uploaded images. Please help!

Hi Hussein,

Sorry you are experiencing these issues. I just ran a test upload with a few different filetypes without an issue. What sort of file types and size are you trying to upload?

2 Likes

Grace/David,

  • When a user attempts to upload a photo in the Retool Mobile app, a loading indicator appears indefinitely (thinking wheel), and an error message "Cannot read property 'endsWith'" is displayed.

  • I've already tried creating a new mobile app, but the same error persists.

  • Note, this issue only occurs when the "Upload file to Retool Storage" interaction is enabled. Disabling it resolves the upload issue.

1 Like

Hi Hussein,

I can confirm I can reproduce this issue when using the mobile device and having the 'Upload to Storage' checked. The mobile team are currently investigating this and will work on a fix asap. In the meantime I have a workaround for you:

You can call an event handler on the ImageInput component to trigger a JS query on the 'close' event (with the 'Upload to Retool Storage' checkbox unticked):


The script it calls will do the following:

This will take the url (hard coded for the first image, but there could be multiple so you can put this in a loop) and convert it to a base64 image. It then onSuccess calls the Retool Storage resource with the image data where it can be uploaded:

*Correction for the Retool Storage Upload final ptep

Thanks for the quick response, Grace! Now, how can I use an image component to display the image from earlier in the detailsScreen ? I'm using a listCollection component right now..


Clicking "Orlando Pizzaro" should open a details screen showing their pictures. How can I use the image21 component to display the pics I saved in Retool storage using that method you mentioned?

My previous method was to use the state of the imageInput component to access the id of the uploaded image, and then write back that id to the database using a SQL query, and then access the image id and insert it into the url parameter of the image21 component in the details screen. Now, I am not sure how to display this image while knowing which form submission it belongs to.

Also, if i save the base64 image information in the database, it slows the performance significantly so that is not a viable option.

storing the image base64 in the Retool Storage shouldn't be any slower.




when you normally store an image the same thing is happening, the image is being stored as a base64 string along with other properties like file type and name. so telling Retool Storage to store a base64 string and giving it the properties it needs shouldn't be much slower if at all. this is also how i'm able to store most img file types and use the base64 data as the source for a <image> element and usually for a <video> element also

what you're essentially doing is storing a file with all the 0's and 1's that make up the image as an unknown file type. you also store the file name and other stuff seperately. so when you retrieve the file, you slap on the file type to the end of the file name and all the sudden your unknown file type is now known. you could see similar results, I'm simplifying this as an example so these steps might not work or differ slightly but it's OS and software dependent. if you open notepad and type stuff in, then click save as and for Save as type select All Files and make sure File Name has the .txt extension at the end. now copy the file, open it and save as but add .mp4 onto the end of the name and leave Save as type the same as before (All Files). you just transferred a file then changed its txt(text/plain) type into a video(video/mp4) type and the OS picks up what to open the file with. this is because when we saved the file with no file type (All Files) and supplied a file extension in the name, the OS changed the file type to match the extension. now right click the .mp4 and click Open With then select Notepad and see the file opens with no problems. this works because the file type isn't stored in the file contents, but as metadata so no matter what the file type is the contents are still just 0's and 1's. it's the same thing here, we're storing the 0's and 1's of an img/video (as a text/plain or image/png file whos contents consist of a fancy base64string) and when we want to get the file, we get the 0's and 1's then rename it adding .mp4 or .png onto the end and updating the metadata. this file we can use as the source for img and video tags, but we can also directly use the base64 as the source for the img and video tags so there's no need to save the file and rename it. instead, we set the source to data:image/png;base64, + base64string and now the image tag has all the 0's and 1's as well as the file type, so it can do everything on it's own. so it doesn't matter if it stores text/plain(which was the result of storing the base64 of a video) or image/png as long as we know the file type for the base64string we can build the source string as data:video/mp4:base64 + base64string or data:image/png:base64 + base64string and the html element will be able to load the data accordingly

Notes:

  • the File Id field in the first pic is set to use a default video if one isn't set/found. that's why it's a bit more complicated. I could just as easily use {{ getIdleVideo.data.file_id[0] }} and just deal with a blank/invalid source later on.
  • in the 3rd pic you could click the fx to the right of File Input to load/build the file name dynamically from other queries and/or variables
  • when storing a file of unknown type in Retool Storage it can't save the file type as All Files so instead it uses text/plain which can be both ascii text or bits (0's and 1's for our example).
  • the 3rd pic shows Retool Storage storing a base64string for a video (when I uploaded it to Retoll Storage I did not provide a file extension, just 1705091955558 as the file name and a base64string as the content). the type is stored as text/plain which is why after I read the contents i transform the results by both adding an encoded property, which is the value I need for the source of image and video elements, and changing the file type to video/mp4 or image/png since I know this is what I stored. If you were saving this locally somehow you would want to add .mp4 to the file name as well, but I'm just using the base64 directly here so I'm not worried about transforming the name. when you're adding an extension (.txt or whatever) to the file name it never affects the file size, but depending on the file type it is possible for the file name itself to affect the size so there's never any need to modify this part before the extension type unless, again, you're saving the file on a hdd somewhere. the image/video source doesn't care about the file name either when you're using a base64string. the only time the file name is important is when saving it locally to easily double-click and open it. you could 100% always ignore the file name and if you save the file to disk just rename it adding the .png or whatever manually which would then let you double-click to open. the process of adding/changing the .extension for the file name to also change the file type and be able to open the file with a default program like notepad, paint, image viewer and so on is due to the File Association set on your OS. This is why you can sometimes see more than 1 file type that opens in Notepad, those file types are unknown to the OS and it defaults to try and open them with Notepad (which can work if it's unknown to the OS but technically it only contains text, like most code files including .js, .sh, .cpp, .c, .h, .py, .html, .csv and so on)

PPPS(? lol) extra note:

  • for those wondering, my example using notepad is based off of file transfers over networks. in the low level you stream all the 0's and 1's over the network. once the receiving end has all the 0's and 1's that make up the file you would have a 'binary file' or the equivalent of a .bin or .dat, basically it's the most simple representation of ANY file, and an easy cheat to get the OS to see these as anything other than text/plain or binary was to append the file extension onto the file name. this even worked for transferring a .exe file
1 Like

Hey Bob, thanks for taking a look!

I appreciate your suggestion, however, it seems quite manual in terms of selecting the image for the frontend from Retool storage.

Context:

  • I have a form where users answer questions and capture a photo.
  • Upon submission, the photo needs storage (Retool storage or a base64 id written back to the SQL table).
  • On the mobile app, a separate navigation tab displays a list of past submissions using a listCollection component to the user.
  • Clicking a specific record should show the related image.
  • Storing base64 IDs in the SQL table was hurting performance.

My Solution:

I proposed storing images in Retool storage using the "save to Retool storage" option, but it's currently not working. Here is what I did when it was working:

  1. Capture the uploadImage component state from the submission form to get the file_id .
  2. Write the file_id (short and lightweight) back to the SQL table.
  3. On the frontend (details of listCollection ), call table1.data.image[0] to retrieve the image for that item. Assuming that the image column contained the stored file_id for that record.

Current Challenge:

Finding an easier way to retrieve the image.

See the earlier screenshots for a visual representation of these steps.

Let me know if you have any other ideas or thoughts on tackling this!

I hope this helps!

This is the state of imageInput1 within the submission form, when upload file to retool storage is checked.

The state gives you retoolStorageID which you can then capture and save to the SQL table. When the upload file to retool storage is unchecked, retoolStorageID state disappears.

Hi grace, any update?

Hi there. This seems to be a fairly urgent issue requiring fix; multiple image upload on mobile is broken, so apps are not working because of it. Any idea when a fix might be out?
The workaround you suggested Grace, doesn't work for multiple images.

We've had the same issue for the last 10 days. We've just stopped using the retool mobile app and use the browser on mobile instead. Much more stable.

Retool mobile app is extremely wonky, especially on Android. Something seems to break every few weeks, with extremely slow fixes. Given that we host business critical applications on retool, it's not just possible to wait a few days and hope that a fix will come our way.

1 Like

quick question, I noticed you're using the old image input (it uses the files property). have you tried with the new input component?

Agreed, I am getting backlashes from the business managers after migrating them from Glide apps to Retool. Its very embarrasing tbh...

It doesn't! and Retool expects you to wait weeks to fix the issue, that is if they even respond!!!!

The issue relates to the mobile set of components. There's only one Image Input component to use.

2024-02-13_09-19-52

Hey folks, this issue should now be fixed in the newest app store apps released today (iOS + Android).

Thank you! Can confirm it is fixed.