Erlang is a dynamic language. It is good practice however to do type checking and static analysis post-compilation.
The tool Dialyzer is used to check for this sort of error condition.
The reason the compiler doesn't know about it at compile time is because functions can be searched for and dynamically loaded from the code path at run time (and also from a remote node). The Dialyzer will check the code against the code path at the time it is run.
The ability to load code from a remote node means that basic 'systems' can be installed on a device and the device can then bootstrap itself from the network.
You should also remember another characteristic of Erlang that you can generate function calls on the fly using constructs like:
erlang:apply(ModuleName, FunctionName, ArgList)
so in that case it is simply not possible to know if the function exists at compile time or not.
And although the module and function might exist now at compile time, you can hot swap modules out and unload code, so it may not be there at run time.