Resource management in Elixir - what happens if between the call to and File.close an error occurs?

Sorry if this was asked before, but i can’t find an answer to this anywhere.

I’m currently learning elixir (i come from a mostly non-functional background go & javascript) there’s something bugging me, in elixir we just let things crash right? and have the supervising process deal with the error but what happens if we do something like

{:ok, f} ="foo.json")
# do things with f
:ok = File.close(f)

What if between the call to"foo.json") and the File.close(f)
an exception occurs this would mean that File.close will never be called does that mean that my process will start leaking resources ? or is the process spawned by is linked to the process calling and will be shutdown and the file handle released when the supervising process shuts down.

Hey @MSE99 welcome! When you open a resource in Elixir / Erlang, that resource is linked to your current process. If that process crashes, the link ensures that the resource is released as well.

Here is a great explanation by @ityonemo
Peeking under the hood of File IO in Elixir

The important piece here is that the runtime doesn’t prevent leaks because the processes opening the file cleans up, but it works because there are multiple processes. Monitors and links are methods a process can use to get notified if another process crashed. This can then be used to trigger cleanup even if the original process requesting the resource is gone.

It is actually not linked, but the process that opened the file is monitored so the resources can be released if it dies.

❯ iex
Erlang/OTP 25 [erts-13.0.1] [source] [64-bit] [smp:10:10] [ds:10:10:10] [async-threads:1] [jit]

Interactive Elixir (1.14.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> self()
iex(2)> {:ok, file} ="test.db")
{:ok, #PID<0.113.0>}
  current_function: {:file_io_server, :server_loop, 1},
  initial_call: {:erlang, :apply, 2},
  status: :waiting,
  message_queue_len: 0,
  links: [#PID<0.58.0>],  # <--------- no link to #PID<0.110.0> here
  dictionary: [],
  trap_exit: false,
  error_handler: :error_handler,
  priority: :normal,
  group_leader: #PID<0.46.0>,
  total_heap_size: 233,
  heap_size: 233,
  stack_size: 4,
  reductions: 102,
  garbage_collection: [
    max_heap_size: %{error_logger: true, kill: true, size: 0},
    min_bin_vheap_size: 46422,
    min_heap_size: 233,
    fullsweep_after: 65535,
    minor_gcs: 0
  suspending: []
Originally sent in Elixir Chat

We open files with right? And we close them using File.close - what if between the call to and File.close an error occurs?

That File.close will never be called and the program will leak that file descriptor?

I know that spawns a process, is that process linked to the process that spawned it?


from the docs of

This function returns:

  • {:ok, io_device} - the file has been opened in the requested mode.io_device is actually the PID of the process which handles the file. This process monitors the process that originally opened the file (the owner process). If the owner process terminates, the file is closed and the process itself terminates too. If any process to which the io_device is linked terminates, the file will be closed and the process itself will be terminated. An io_device returned from this call can be used as an argument to the IO module functions. also takes a callback. File will be closed automatically after the callback.




  • if an exception is raised without being catched, then the process will be killed (by default), and all the related resources will be garbage-collected.
  • if an exception is raised, and you can catch it, then you still have the chance to call File.close.

(oops made a mistake)