SyntaxError during deployment build but not local build

I just encountered an interesting error. I have a Phoenix controller with the following guard statement:

  @valid_types ["servicer", "bank", "credit-card"]

  def index(conn, %{"type" => type}) when type in @valid_types do
    conn
    |> put_status(200)
    |> render("index.json", data: Institution.get_onboarding_list(type))
  end
  def index(conn, %{"type" => type}) when type not in @valid_types do
    conn
    |> put_status(400)
    |> render(ErrorView, "query_params.json")
  end

This controller function compiles on my machine locally with no problems. When I run the server locally and call the route the guard behaves correctly. I have tests which pass too.

However, when I deploy I get the following SyntaxError related to the not in in the guard statement in the second function clause.

[2017-10-02 23:47:52.291] [stdout]== Compilation error on file web/controllers/institution_controller.ex ==
[2017-10-02 23:47:52.306] [stdout]** (SyntaxError) web/controllers/institution_controller.ex:15: syntax error before: in
[2017-10-02 23:47:52.306] [stdout]    (elixir) lib/kernel/parallel_compiler.ex:117: anonymous fn/4 in Kernel.ParallelCompiler.spawn_compilers/1

Anyone seen anything like this before?

I just found out my deployment machine is running Elixir 1.4.5 and I’m developing on 1.5. Might have something to do with it…

The problem is this:

def index(conn, %{"type" => type}) when type not in @valid_types do

I believe the correct syntax is when not type in instead of when type not in.

On a side note, the second function is logically implied, so you don’t need a guard clause there. For example, this will match anything that wasn’t picked up by your first function head:

def index(conn, _params) do
  conn
  |> put_status(400)
  |> render(ErrorView, "query_params.json")
end
1 Like

Huh, I wonder why the compiler didn’t catch that on my local machine.

I actually have one more case I didn’t mention, index(conn, _params) I’m using to get the institutions for a logged-in user who’s JWT is in the conn. That’s why I went to the trouble of writing those two function clauses.

Thanks for the response!

x not in y is valid and preferred in Elixir 1.5 and above. Your build server’s Elixir is out of date.

2 Likes

You can (and should) set the Elixir version in mix.exs:

  def project do
    [app: :my_app,
     version: "0.1.0",
     elixir: "~> 1.5",
     #...
  end

You’ll then see an error when compiling that looks like:

** (Mix) You’re trying to run :my_app on Elixir v1.4.5 but it has declared in its mix.exs file it supports only Elixir ~> 1.5

2 Likes