Strange behaviour when using LiveView Uploads on Fly.io - {:error, :enoent} but not every time

Hi,

I have a small LiveView app deployed on Fly.io and sometimes, when uploading an image, I encounter strange behavior. I click browse, I select image and image preview shows, I click submit and image is uploaded, this is how it should work and works most of the time, but sometimes, something happens and uploading breaks.

In fly logs, I get {:error, :enoent} error. I used dbg to see if the file exists, and it does. So, the file exists and when it should be copied from /tmp/ folder to /uploads folder, it breaks for some reason.

As I already mentioned, this is happening only sometimes, most of the time it works fine and that makes it quite hard to debug. This doesn’t happen on my dev machine. Do you have any idea what could be causing this kind of behavior?

FILE EXISTS: /tmp/plug-1711-iIkC/live_view_upload-1711634767-822835485870-1
COPY ERROR: enoent
[lib/myapp/helpers/file_manager.ex:60: MyApp.Helpers.FileManager.copy_file/2]
path #=> "/tmp/plug-1711-iIkC/live_view_upload-1711634767-822835485870-1"
[lib/myapp/helpers/file_manager.ex:61: MyApp.Helpers.FileManager.copy_file/2]
dest #=> "/uploads/tmp/live_view_upload-1711634767-822835485870-1.jpg"
warning: consuming uploads requires a return signature matching:
    {:ok, value} | {:postpone, value}
got:
    {:error, :enoent}
defp copy_file(path, dest) do
    case File.cp(path, dest) do
      :ok ->
        {:ok, nil}
      {:error, reason} ->
        {:error, reason}
    end
  end

Maybe it has to do with the tmp file being deleted after the process ends?

Did this happen for big image files?

Do You try to save in async mode?

The log shows it’s being copied to /uploads/tmp/live_view_upload-1711634767-822835485870-1.jpg - does that tmp subdirectory always exist inside uploads?

The :enoent from cp is what I’d expect when it doesn’t exist.

No, the file in the /tmp/ folder exists when the error is thrown so the process doesn’t ends before the error.

It doesn’t matter, I’ve tested with several images, from 200kb to 3mb, and it can happen to any of them.

No.

Files are uploaded by default to /tmp dir. Then, I copy them to /uploads/tmp (this is where the problem occurs) where I do some transformations to the image and then, the image is saved to a custom user dir. After image is successfully saved to the user dir, image is removed from /uploads/tmp but the subdir tmp remains.

Exactly, that’s the problem which I don’t understand. I’ve checked with File.exists?() and the file is there even after the error is thrown.

Probably not it, but on fly is everything happening on the same server/machine? Wondering if the connection is occasionally getting bounced to another machine which would explain it. The code looks like it would only execute on one machine though.