Mix release eval - does runtime.exs have access to compiled config?

I’m using mix release to build and deploy releases of a Phoenix and Ecto app, but eval is not running like I want it to.

The correct app configs are loaded if I use e.g bin/myapp start_iex - I get (what was originally) config.exs + included stage.exs + runtime.exs.

However, if I attempt bin/myapp eval 'something' (where ‘something’ is any command that would normally work, like migrations), the eval fails before executing anything.

The error message is

ERROR! Config provider Config.Reader failed with:
** (FunctionClauseError) no function clause matching in Keyword.fetch!/2
    (elixir 1.13.4) lib/keyword.ex:556: Keyword.fetch!(nil, :enabled?)
    (stdlib 3.17.1) erl_eval.erl:685: :erl_eval.do_apply/6
    (stdlib 3.17.1) erl_eval.erl:476: :erl_eval.expr/5
    (stdlib 3.17.1) erl_eval.erl:270: :erl_eval.expr/5
    (elixir 1.13.4) src/elixir.erl:296: :elixir.recur_eval/3
    (elixir 1.13.4) src/elixir.erl:274: :elixir.eval_forms/3
    (elixir 1.13.4) lib/code.ex:404: Code.validated_eval_string/3
    (elixir 1.13.4) lib/config.ex:260: Config.__eval__!/3

I get this even if I try to eval 'Application.load(:myapp)'.

I suspect it is because my runtime.exs attempts to read the compile-time config:

import Config

vault_opts = Application.get_env(:myapp, :vault)

#vault_opts is nil when runtime.exs is run in eval, so the next line crashes
if Keyword.fetch!(vault_opts, :enabled?) == true do
  # ...
end

So… reading the compile-time config works okay for start_iex but not for eval? I can’t tell what I’m missing.

1 Like

eval “EXPR” Executes the given expression on a new, non-booted system

“non-booted system” means non of the applications are loaded. The app env of an application is only available if the application has been loaded before. So this is expected.

I guess this is my confusion - if the application is not loaded, why is runtime.exs being invoked by eval - it would have no config env to inject its values to, right?

The way it works is that, once an application is loaded, it gets the environment from its .app file, merges the things that were evaluated from configuration in, and then make it available via the get_env APIs.