Elixir’s “module is not available” error can drive you nuts.
But fear not:
After writing a lot of Elixir and seeing this error often, I’ll developed a few quick tricks that you can use to solve why your module is not available in seconds instead of minutes.
Here’s 4 quick things you can check.
Check Your Module Definition
This almost goes without saying, but every time I don’t check the module definition first, it turns out I’ve misspelled one of my module definitions.
Check the top (usually top) of your file for your
defmodule function. Some things to look for are that everything is spelled correctly, i.e.
App.User and not
App.Users, that you have included your application name if needed, i.e.
User, that you are using the proper punctuation, i.e.
Did You Forget to include
Sometimes, in a bout of “in the zone” programming, you may have written a call to a module that you believed you had aliased, but forgot to include the
alias function call.
For example, trying to call
User.full_name() when the full function call is
App.User.full_name() would result in the module is not available error.
App.User, in this case, would need to be aliased first.
Inspect Loaded Modules
Still can’t find the module? Well, one debugging trick is to check a list of all the currently loaded, user-defined modules in the application.
There’s two ways you can do this:
First, you can check the
my_app.app compiled file in your
Specifically, this file is usually located in:
While this file may appear a bit cryptic, you can probably ascertain what the
modules entry shows. It’s a list of user-defined modules available to your application from compilation.
The second trick is:
:application.get_key(:my_app, :modules) wherever the module is not available error is occurring. Combine this with the
IO.inspect/1 function and it will show you all of the available user-defined Elixir modules at that point in time.
IO.inspect :application.get_key(:my_app, :modules)
It’s a quick way to see all the user-defined Elixir modules available to the
:my_app application at that point in your Elixir application.
Using this Elixir debugging trick may allow you to catch if you have badly misspelled a module or perhaps forgot to include a module for compilation.
Which brings us to my last tip:
Make Sure Your Module is Available to Your Application
My last tip is the most complex in terms of implementation and understanding.
But here goes:
You need to check that your Elixir module is available to your application by telling the
elixirc compiler to generate a
.beam file for your module.
Why would the Elixir compiler not compile a
.beam file? Well, 2 common reasons:
- You placed the module in a directory outside of
liband did not
tell the compiler.
You used the
.exsextension instead of
The first reason can be puzzling if you do not realize the problem. By default, the Elixir compiler only looks to compile files and load modules located in the
lib directory of an Elixir application.
As your Elixir application complexity increases, you may decide to include Elixir modules that need to be compiled outside of the
lib directory. A good example of this are modules that may be used for supporting tests such as mocks.
The solution to this problem is straightforward, but a bit hidden in the Elixir documentation.
You need to tell the Elixir compiler the directory where your modules are located.
To do this, you need to use the Elixir
elixirc_paths option in your project configuration. All you need to do is set the
elixirc_paths key to a list of paths of the directories that you want the Elixir compiler to compile.
Here’s the catch:
In many cases, you probably do not want to compile the same files across different environments.
For example, in a production environment, you may not want to compile the modules that you use for your test environment.
To get around this, we can use a function that we define in
mix.exs that returns a different lists of paths depending on the environment.
In fact, this is exactly what Phoenix Framework does by default in new projects.
def project do [ ... elixirc_paths: elixirc_paths(Mix.env), ... ] end # Specifies which paths to compile per environment. defp elixirc_paths(:test), do: ["lib", "test/support"] defp elixirc_paths(_), do: ["lib"]
You can see in the code above the
elixirc_paths/1 function includes the “test/support” directory in the Elixir compiler paths for the test environment, but not for other environments such as development.
Setting this directory in the Elixir compiler paths means that any modules defined within
.ex extension files will automatically be compiled and their modules loaded for your application.
Which brings me to the second issue:
Another mistake that you may make is to use the
.exs extension instead of the
.ex extension. You may be defining Elixir modules that you need to compile for use in your application in files with a
.exs extension is used for scripting. Like the
.exs files are compiled, their modules loaded, and executed.
It is very well documented that
.ex extension files get compiled down to
.beam files. The modules in your compiled
.beam files get loaded by your application automatically when the application starts.
However, the compiled BEAM bytecode from
.exs files does not get output into a
.beam file the way that
.ex files do. They are, in essence, ephemeral. They are compiled, loaded, and executed, and then disappear. Hence, if you are trying to access a module in an
.exs file from your application, it will fail with the “module not available” error.
Hope this information was helpful. If you have any questions or have another tip, feel free to leave a comment below.
This post is part of my series of Elixir Tutorials
Hey, I’m Adam. I’m guessing you just read this post from somewhere on the interwebs. Hope you enjoyed it. When I’m not writing these blog posts, I’m a freelance Elixir and Ruby developer and working on Calculate, a product which makes it easier for you to create software estimates for your projects. Feel free to leave a comment if you have any questions.
You can also follow me on the Twitters at: @DeLongShot