System.get_env behaviour with non-existent environment variable

Hello, everyone. :slight_smile: This is my first question here, but Iā€™ve found a lot of helpful discussions so I first want to say thank you for that.

Now, I when I have System.get_env(ā€œNOT_DEFINED_VARIABLEā€) in my application, it seems to return true even if in the console it returns nil. Is this expected and why does it happen?

I used IO.puts to check itā€™s value in the application itself, but I also tried using it in conditionals.

2 Likes

Can you provide a code snippet that shows your problem?

On my system it seems to work as documented

2 Likes

Ditto:

ā•°ā”€āž¤  iex
Erlang/OTP 20 [erts-9.1] [source] [64-bit] [smp:2:2] [ds:2:2:10] [async-threads:10] [hipe] [kernel-poll:false]

Interactive Elixir (1.6.0-dev) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> System.get_env("NOT_DEFINED_VARIABLE")
nil
2 Likes

What Overmind wrote was the same for me.
The problem is when I do IO.puts(System.get_env("NOT_DEFINED_VARIABLE")) in my phoenix app with the same variable that returned nil in the console - and I tried it in one of the router pipelines and in a plug module - it returns true.

Nobbz, thatā€™s basically the code:
IO.puts(System.get_env("NAME_OF_UNDEFINED_ENV_VAR"))
And it returns true from the app.

My goal was to use it in a conditional statement such as

if System.get_env("SOME_ENV_VAR") do
   do something only if the env var above is present
end

But it seemed to run even if it was not defined, which is why I tried what I mentioned in the question.

1 Like

What does return true and how do you see it is returning true?

System.get_env/1 canā€™t return true, it returns either a string or nil but not true.

1 Like

Works for me:

iex(2)> if System.get_env("FOOO"), do: :set, else: :not_set
:not_set
$ elixir foo.exs
:not_set
$ cat foo.exs
IO.inspect if System.get_env("FOOO"), do: :set, else: :not_set
1 Like

I think itā€™s a narrower problem - I tried changing the name of the undefined env var and doing IO.puts in the app and it returned nil.

However, the environment variable with the name I originally used is not defined anywhere (this is locally), not in the code, not in a .env file, yet for some reason using System.get_env/1 with it returns true.

I still donā€™t know why though. I have used source .env, but my .env file has only two variables that are different.

1 Like

Again, System.get_env/1 can not return true, never!

It can return either a String.t (which is always a truethy value, but not true) or nil (which is a falsy value but not false). So please show the exact code which makes you assume it were returning true.

3 Likes

*Edited with better example.

This is what I tried.

  pipeline :browser do
    plug :accepts, ["html"]
    IO.puts("Before")
    IO.puts(System.get_env("NON_EXISTENT_ENV_VAR"))
    IO.puts("After")
    plug BasicAuth
    plug :fetch_session
    plug :fetch_flash
    plug :protect_from_forgery
    plug :put_secure_browser_headers
  end

This is after starting the app:

I might have defined this variable before, but that was definitely not in the last few days and the app has been compiled many times after that for sure. I have also sourced a .env file without it numerous times even if it was defined in it at some point.

Also, as I mentioned - if I use a name that I have never before written in the app for an env var, it properly returns nil, and if I use the same name as above in the console it returns nil, too.

1 Like
  1. Its probably returning "true", but thats only a guess, please use IO.inpect/2 to be sure.
  2. in the exact same shell session that has created this output, please try env | grep NOT_DEFINED_VARIABLE
  3. To be really sure please do unset NOT_DEFINED_VARIABLE; mix do clean, phx.server

Steps 2 and 3 are to make sure it is not your shell environment. If we know it isnā€™t coming from there, we know it must be your application.

2 Likes

After running step 3 it shows nil. Thank you. :slight_smile:
Could you please explain why it might have happened? I was trying to use it in a conditional statement and let it be defined only on the server, and was quite baffled by this.

1 Like

Well, steps 1. and 2. didnā€™t change anything, they were just to produce output, which you havenā€™t shown to us.

  1. After applying 1, did your output change from true to "true"?
  2. When doing 2, did you have an output? How did it look like?
  3. After applying 3, you unset the environment variable that you had set elsewhere. I do not know where, how and when you set your environment variables. Apparently the supposed to not exist variable did indeed exist and hat the value "true".

But be aware, as you have shown it to us, the variable is checked during compile time, so it will only get checked at the computer that compiles the application not on the computer it will run on laterā€¦

2 Likes

Excuse me about that, I forgot 1 and tried 2 in the wrong way (donā€™t ask me how) and then went to 3.
Iā€™ll get some sleep and try to reproduce this issue.

I think I might have defined it as true at some point. Locally, Iā€™ve just used a .env file and I wonder why it persisted after having restarted the app multiple times and running source .env without it multiple times.

Thank you for your last advice, Iā€™ll have to rethink that I guess. And thank you for the answers. Once again, excuse me for being of little help. I will try to reproduce the issue when I get some rest.

1 Like

I think I might have defined it as true at some point. Locally, Iā€™ve just
used a .env file and I wonder why it persisted after having restarted the
app multiple times and running source .env without it multiple times.

Sourcing a file doesnā€™t replace whatā€™s defined in your environment
with its content; it updates or adds to it.

Enter the command env at a shell prompt and youā€™ll see everything
defined, a lot of which certainly didnā€™t come from your .env file.

1 Like

Why do you think you need to do different things depending on the computer you are on?

1 Like

Hassan, thank you. :slight_smile:

Nobbz, Iā€™ll first say I just trying add the environment variable to my .env file, sourced it, then removed it and sourced again but it stayed in my shell environment, as you mentioned, so I guess thatā€™s what had happened.

About your last question, letā€™s say I have a phoenix application running on AWS Elastic Beanstalk with Docker and I want basic authentication. I added the plug, and it was working alright.
However, I also have an AWS SQS queue and another worker application with the same configuration as the first one which is supposed to get the messages from the queue without basic authentication. Thatā€™s why I decided to try using an environment variable that would be defined only in the worker application, and check for it to bypass the basic authentication.

1 Like

You are speaking about a program which is kind of master when running on Aws but kind of worker on any other computer. Are you sure that these arenā€™t distinct apps with a shared set of modules?

1 Like

Excuse me for the late reply.
The worker is also on AWS, itā€™s just an environment that receives queue messages instead of the main application. I guess terming it as ā€˜worker applicaitonā€™ wasnā€™t very right. Thatā€™s what the AWS documentation says:

The environment tier that you choose determines whether Elastic Beanstalk provisions resources to support an application that handles HTTP requests or an application that pulls tasks from a queue. An application that serves HTTP requests runs in a web server environment. An environment that pulls tasks from an Amazon Simple Queue Service queue runs in a worker environment.

Excuse me for the late reply - reflecting back, I believe, and I have to admit how stupid I was, that System.get_env/1 in my case was just returning a true as a string, not as a boolean. Iā€™m sorry for taking everyoneā€™s time. In any case, thank you all!

2 Likes