Error with clause matching after updating to V1.10.4 in Kernel.=~/2

I’ve just upgraded Elixir from 1.7.4 to 1.10.4 and I’m having some problems after creating a release. The development environment works just fine using

iex -S phx.server

However, when I build it using

MIX_ENV=prod mix release

and run it _build/.../bilula start

I get this error

** (Mix) Could not start application bilula: Bilula.start(:normal, []) returned an error: shutdown: failed to start child: BilulaWeb.Endpoint
    ** (EXIT) an exception was raised:
        ** (FunctionClauseError) no function clause matching in Kernel.=~/2
            (elixir 1.10.4) lib/kernel.ex:2011: Kernel.=~(nil, ~r/[^:]:\d/)
            (phoenix 1.5.13) lib/phoenix/endpoint/supervisor.ex:345: Phoenix.Endpoint.Supervisor.build_url/2
            (phoenix 1.5.13) lib/phoenix/endpoint/supervisor.ex:281: Phoenix.Endpoint.Supervisor.url/1
            (phoenix 1.5.13) lib/phoenix/config.ex:54: Phoenix.Config.cache/3
            (phoenix 1.5.13) lib/phoenix/endpoint/supervisor.ex:476: Phoenix.Endpoint.Supervisor.log_access_url/3
            (phoenix 1.5.13) lib/phoenix/endpoint/supervisor.ex:17: Phoenix.Endpoint.Supervisor.start_link/3
            (stdlib 3.12.1.2) supervisor.erl:379: :supervisor.do_start_child_i/3
            (stdlib 3.12.1.2) supervisor.erl:365: :supervisor.do_start_child/2

Here are my deps:

defp deps do
    [
      {:amqp, "~> 3.1"},
      {:arc, "~> 0.11.0"},
      {:bamboo, "~> 1.2"},
      {:bamboo_smtp, "~> 1.3"},
      {:bcrypt_elixir, "~> 1.0"},
      {:briefly, "~> 0.3"},
      {:bypass, "~> 1.0", only: :test},
      {:comeonin, "~> 4.0"},
      {:cors_plug, "~> 1.5"},
      {:credo, "~> 0.5", only: [:dev, :test], runtime: false},
      {:css_colors, "~> 0.2.1"},
      {:csv, "~> 2.0"},
      {:distillery, "~> 1.2", runtime: false},
      {:ecto_sql, "~> 3.1.4"},
      {:ex_aws, "~> 2.0"},
      {:ex_aws_s3, "~> 2.0"},
      {:ex_doc, "~> 0.21", only: :dev, runtime: false},
      {:ex_machina, "~> 2.1", only: :test},
      {:excoveralls, "~> 0.12.2", only: :test, runtime: false},
      {:exq, "~> 0.13.0"},
      {:recaptcha, "~> 3.0"},
      {:flow, "~> 0.14"},
      {:gettext, "~> 0.13"},
      {:guardian, "~> 1.2.1"},
      {:hackney, "~> 1.15.2", override: true},
      {:hammer, "~> 6.0"},
      {:html_sanitize_ex, "~> 1.3.0"},
      {:httpoison, "~> 1.0"},
      {:inflex, "~> 1.10"},
      {:jason, "~> 1.1"},
      {:libcluster, "~> 3.0"},
      {:logger_file_backend, "~> 0.0.10"},
      {:logster, "~> 0.4"},
      {:mox, "~> 0.3", only: :test},
      {:navigation_history, "~> 0.2.2"},
      {:neuron, "~> 5.0.0"},
      {:nimble_csv, "~> 0.3"},
      {:telemetry_poller, "~> 0.4"},
      {:telemetry_metrics, "~> 0.6"},
      {:open_api_spex, "~> 3.10"},
      {:phoenix, "~> 1.5.13"},
      {:phoenix_live_view, "~> 0.15.0"},
      {:floki, ">= 0.0.0", only: :test},
      {:phoenix_ecto, "~> 4.0"},
      {:phoenix_html, "~> 2.14.1"},
      {:phoenix_live_reload, "~> 1.0", only: :dev, runtime: false},
      {:phoenix_pubsub, "~> 2.0"},
      {:phoenix_live_dashboard, "~> 0.4"},
      {:plug, "~> 1.12"},
      {:plug_cowboy, "~> 2.0"},
      {:poison, "~> 3.1"},
      {:postgrex, "~> 0.14.3"},
      {:prometheus, "~> 4.0", override: true},
      {:prometheus_ecto, "~> 1.4.0"},
      {:prometheus_ex, "~> 3.0", override: true},
      {:prometheus_phoenix, "~> 1.2.0"},
      {:prometheus_plugs, "~> 1.1.1"},
      {:prometheus_process_collector, "~> 1.3"},
      {:redix, "~> 0.9.3"},
      {:scrivener_ecto, "~> 2.0"},
      {:scrivener_headers, "~> 3.1"},
      {:scrivener_list, "~> 2.0"},
      {:sentry, "~> 7.0"},
      {:swarm, "~> 3.0"},
      {:sweet_xml, "~> 0.6"},
      {:tap, "~> 0.1.5"},
      {:timex, "~> 3.3.0"},
      {:xlsxir, "~> 1.6.2"},
      {:hound, "~> 1.1.0"},
      {:jose, "~> 1.10.1"},
      {:tesla, "~> 1.4"},
      {:vaultex, "~> 1.0.1"},
      {:mix_audit, "~> 1.0", only: [:dev, :test], runtime: false},
      {:mock, "~> 0.3.0", only: :test}
    ]
  end

And my elixir -v output:

 elixir -v               
Erlang/OTP 22 [erts-10.7.2.18] [source] [64-bit] [smp:10:10] [ds:10:10:10] [async-threads:1]

Elixir 1.10.4 (compiled with Erlang/OTP 22)

I’ve double checked and there is no nil value in my prod.exs or my runtime.exs

From my last Elixir job I distinctly remember that between 1.9 and 1.10 there were breaking changes in the release process. Or maybe we switched away from Distillery to the native releases – sadly I can’t remember now.

I suggest you upgrade one minor version at a time – in this case upgrade to 1.8 first.

When you get to the problem, go inspect Elixir’s changelog – it usually contains warnings about what to change if something can break.

Sorry I can’t help more. Maybe I can dig something in my bookmarks describing the process but I can’t promise it.

Yeah you need to upgrade distillery and use mix distillery.release because somewhere in there Elixir got its own built in release tool which got mix release. Alternatively you can switch over to using the built in mix release, but that’ll probably require regenning your release config.

2 Likes

Although distillery is a dependency we are not using it, I actually removed it from mix.exs after noticing from your comment.

I’m trying to use the built in mix release, and using it is generating the error I showed before.

Were you using releases before the upgrade?

No I wasn’t, I was using mix release already

Digging a little more into it and found out that this is the piece of code that breaks

#Phoenix.Endpoint.Supervisor
defp build_url(endpoint, url) do
    https = endpoint.config(:https)
    http  = endpoint.config(:http)

    {scheme, port} =
      cond do
        https ->
          {"https", https[:port]}
        http ->
          {"http", http[:port]}
        true ->
          {"http", 80}
      end

    scheme = url[:scheme] || scheme
    host   = host_to_binary(url[:host] || "localhost")
    port   = port_to_integer(url[:port] || port)

    if host =~ ~r"[^:]:\d" do
      Logger.warn("url: [host: ...] configuration value #{inspect(host)} for #{inspect(endpoint)} is invalid")
    end

    %URI{scheme: scheme, port: port, host: host}
  end

Taking a look at the error stack, the problem is that host is nil in the if clause.

Checked my Application file and this is how I’m starting the Endpoint:

#Bilula.ex
use Application
children = [
      BilulaWeb.Telemetry,
      BilulaaWeb.Endpoint,
      ...
]

Don’t really know where nil is coming from…

This is the bit you’re confused about. On Elixir 1.7.4 if you type mix release what you are doing is making a distillery release not a release from mix itself, because mix didn’t have built in release support. Now on the later Elixir version you are using mix release runs code inside of mix itself because it got first class release support.

To stick with using distillery, you now have to do mix distillery.release. To change over to Mix’s built in release tool, you’ll need to probably re-generate your release configuration. For more information on that see How I migrated my pet project from distillery to elixir releases - The Crafting Strider

2 Likes

Nice link, thank you. Instant bookmark.

I was definitely confused about it. Just read a little bit more and now what you said makes sense… I was indeed using distillery before (just didn’t knew about it) and now I want to use the built in option.

I carefully read the link you sent (thanks, by the way). Changed everything it states but after creating a new release and try to run in the server…

** (Mix) Could not start application bilula: Bilula.start(:normal, []) returned an error: shutdown: failed to start child: BilulaWeb.Endpoint
    ** (EXIT) an exception was raised:
        ** (FunctionClauseError) no function clause matching in Kernel.=~/2
            (elixir 1.10.4) lib/kernel.ex:2011: Kernel.=~(nil, ~r/[^:]:\d/)
            (phoenix 1.5.13) lib/phoenix/endpoint/supervisor.ex:345: Phoenix.Endpoint.Supervisor.build_url/2
            (phoenix 1.5.13) lib/phoenix/endpoint/supervisor.ex:281: Phoenix.Endpoint.Supervisor.url/1
            (phoenix 1.5.13) lib/phoenix/config.ex:54: Phoenix.Config.cache/3
            (phoenix 1.5.13) lib/phoenix/endpoint/supervisor.ex:476: Phoenix.Endpoint.Supervisor.log_access_url/3
            (phoenix 1.5.13) lib/phoenix/endpoint/supervisor.ex:17: Phoenix.Endpoint.Supervisor.start_link/3
            (stdlib 3.12.1.2) supervisor.erl:379: :supervisor.do_start_child_i/3
            (stdlib 3.12.1.2) supervisor.erl:365: :supervisor.do_start_child/2

Could it be because of the way I’m creating the Endpoint config in my prod.exs?

config :bilula, BilulaWeb.Endpoint,
  http: [port: 4000],
  url: [host: {:system, "HOSTNAME"}, port: 4000],
  server: true,
  root: ".",
  version: Mix.Project.config()[:version],
  secret_key_base: "..."

That line is this phoenix/lib/phoenix/endpoint/supervisor.ex at v1.5.13 · phoenixframework/phoenix · GitHub which says that HOSTNAME isn’t being set correctly. What do you have in your runtime.exs? Your prod.exs will get set at build time, not when your release is run.

config/runtime.exs is Elixir 1.11+ only. 1.10 would have config/releases.exs available though.

Guys, I’ve removed this line:

url: [host: {:system, "HOSTNAME"}, port: 4000],

And now I’m having some errors with amqp. Depending on the point of view, guess I can call it a progress. I’ll take a look at the changelogs and migration process of the lib since I’ve updated amqp from 1.2.2 to 3.1

** (Mix) Could not start application bilulaa: Bilula.start(:normal, []) returned an error: shutdown: failed to start child: AMQPClient.Supervisor
    ** (EXIT) shutdown: failed to start child: PoseidonSender
        ** (EXIT) exited in: GenServer.call(AMQPClient.Connection, :get_connection, 5000)
            ** (EXIT) an exception was raised:
                ** (ArgumentError) expected argument to be a literal atom, literal keyword or a :amqp_params_network record, got runtime: {:amqp_params_direct, "bilula", "why-would-they-print-the-password??", "bilula", :nonode@nohost, :none, []}
                    (elixir 1.10.4) lib/record.ex:506: Record.__keyword__/3
                    (amqp 3.1.1) lib/amqp/connection.ex:202: AMQP.Connection.merge_options_to_amqp_params/2
                    (amqp 3.1.1) lib/amqp/connection.ex:179: AMQP.Connection.do_open/3
                    (bilula 24.45.8) lib/AMQP/connection.ex:41: AMQPClient.Connection.handle_info/2
                    (stdlib 3.12.1.2) gen_server.erl:637: :gen_server.try_dispatch/4
                    (stdlib 3.12.1.2) gen_server.erl:711: :gen_server.handle_msg/6
                    (stdlib 3.12.1.2) proc_lib.erl:249: :proc_lib.init_p_do_apply/3

but if you have any idea, I’m listening

Hi @pneri1 this will work better if you can answer some of the questions that have been asked. We didn’t say to remove the line, we asked if there is a releases.exs file or not. You have a general problem with how your environment variables and other config is being set, removing a line or two isn’t going to solve your problem.

Sure, I don’t have any release.exs nor runtime.exs files in this project