Environment Variable not loading with load_dotenv() in Linux
Asked Answered
F

8

12

I'm trying to make a discord bot, and when I try to load a .env with load_dotenv() it doesn't work because it says

Traceback (most recent call last):
  File "/home/fanjin/Documents/Python Projects/Discord Bot/bot.py", line 15, in <module>
    client.run(TOKEN)
  File "/home/fanjin/.local/lib/python3.8/site-packages/discord/client.py", line 708, in run
    return future.result()
  File "/home/fanjin/.local/lib/python3.8/site-packages/discord/client.py", line 687, in runner
    await self.start(*args, **kwargs)
  File "/home/fanjin/.local/lib/python3.8/site-packages/discord/client.py", line 650, in start
    await self.login(*args, bot=bot)
  File "/home/fanjin/.local/lib/python3.8/site-packages/discord/client.py", line 499, in login
    await self.http.static_login(token.strip(), bot=bot)
AttributeError: 'NoneType' object has no attribute 'strip

Here's my code for the bot:

import os

import discord
from dotenv import load_dotenv

load_dotenv()
TOKEN = os.getenv('DISCORD_TOKEN')

client = discord.Client()

@client.event
async def on_ready():
    print(f'{client.user} has connected to Discord!')

client.run(TOKEN)

And the save.env file: (It's a fake token)

# .env
DISCORD_TOKEN={XXXXXXXX}

Both files are in the same directory, and I even tried to explicitly specify the .env's path with

env_path = Path('path/to/file') / '.env'
load_dotenv(dotenv_path=env_path)

but that also didn't work

Filide answered 8/11, 2020 at 1:49 Comment(11)
Insofar as this is principally a question about the dotenv library, which isn't part of Python or Linux itself, consider tagging for that library.Philcox
BTW, this is a guess, but does it work if you quote your token's value? That is: DISCORD_TOKEN='{...}'Philcox
...it would also be helpful to include the stack trace for the exception; if we know which line originally threw the exception, we'll know which value was unexpectedly None instead of containing a string.Philcox
@CharlesDuffy Sorry for getting to you late, I'm using the python-dotenv library I installed with pip. I tried quoting it but it didn't work, and I updated the post to include the full stack traceFilide
Okay, so that error is telling you that token is None; it's not being directly thrown from the dotenv code itself.Philcox
Have you checked that the current working directory of your script is the same as the directory the code is in? Log the path so you know it's correct, and then we can move on to other issues (like checking whether dotenv can handle curly braces in values).Philcox
If you're running your script as a systemd service, by the way, have you considered using the EnvironmentFile directive to have systemd load the variables from your file before the Python interpreter is even started?Philcox
Yes, it is in the same working directory, and I also tried it without curly brackets. Also, what do you mean by running my script as a systemd service? And how do I use the EnvironmentFile directive?Filide
Waitaminute. When you say "same working directory", that doesn't make it clear to me that you know what the term "current working directory" means. I'm asking if you know, with absolute certainty, that the current working directory of the process (the directory returned by os.getcwd()) is the same as the directory that contains both your code and your .env. That's not necessarily the case, and there are good reasons to make it not the case (a cwd of / avoids whole classes of bugs, f/e, the potential for a working directory to become invalid).Philcox
An EnvironmentFile directive is part of systemd service configuration. If you're telling systemd to run your service for you, you create a .service file that tells you how you want that service to be run (so if you called it my-discord-bot.service, you could then use systemctl start my-discord-bot to start it, or journalctl -u my-discard-bot to read its logs).Philcox
One of the things you can put in that service definition file is a list of other files to read to get environment variables. (You can also configure whether you want your service automatically restarted on reboot, which services it should be started after, etc etc).Philcox
B
10

TL:DR

You need to put the full path.

Use

  • either os.path.expanduser('~/Documents/MY_PROJECT/.env')

  • or: load_dotenv('/home/MY_USER/Documents/MY_PROJECT/.env')

and it will work.

Or you change your current working directory in your code editor to where the ".env" file is (which should be the project folder).

Or you open the project folder in the menu of your code editor, this should make the project folder the current working directory.

On Linux, you can also go to the project folder in the terminal and start the code editor from there, type for example codium or whatever you use in the command prompt.

Background

Quote from the other answer

Since, I moved my .env file's inside another subfolder config, then I had to provide the full path to load_dotenv() to make it work.

This gave me the idea of checking the working directory.

Current working directory

os.getcwd() gave me a folder further up the tree. And then I copied the ".env" file into that working directory and it worked.

Changing the working directory depends on your code editor. I use codium, which is the open source version of vscode, then you may follow for example Python in VSCode: Set working directory to python file's path everytime

Full path

You can also put the full path.

Funny enough, I had checked that before coming here, but I copied the path that you get from the terminal, starting with '~/Documents/MY_PROJECT, which does not find the file but does not alert either, any tried environment variables were just empty - just because the ".env" file itself was never read.

Bucephalus answered 20/1, 2022 at 19:49 Comment(0)
G
13
I was facing a similar issue and found out these three possible solutions/reasons:
  1. Check if the syntax in your .env file is correct or not, the original documentation will be the best source - Python Dotenv (sample below)

     DOMAIN=example.org
     ADMIN_EMAIL=admin@${DOMAIN}
     ROOT_URL=${DOMAIN}/app
    
  2. The solution which worked for me, was using find_dotenv() instead of file path inside load_dotenv(), the reason is load_dotenv() doesn't load the .env file properly. find_dotenv() is a function that automatically finds .env file if it's located in the same folder as your code file.

     from dotenv import load_dotenv, find_dotenv
    
     load_dotenv(find_dotenv())
    
  3. You can limit your search to the current project folder using sys.path[1] to make sure you're reading the intended file.

     import sys
     from dotenv import load_dotenv
     load_dotenv(sys.path[1]) #try .path[0] if 1 doesn't work
    

Since, I moved my .env file's inside another subfolder config, then I had to provide the full path to load_dotenv() to make it work.

import sys
from dotenv import load_dotenv
path = sys.path[1]+'/config/.env'  #try .path[0] if 1 doesn't work
load_dotenv(path)

[edited]

Goodson answered 14/9, 2021 at 19:50 Comment(0)
B
12

I had a similar issue, and in my case, this solved it:

Instead of doing load_dotenv() I needed to do load_dotenv(override=True). This was because I had set one of the variables from the .env file manually, and so it was not updating with the value set in the .env file.

The parameter override defaults to False. Here is the definition, taken from the dotenv github:

override: Whether to override the system environment variables with the variables
            from the `.env` file.
Bottommost answered 21/6, 2023 at 23:24 Comment(0)
B
10

TL:DR

You need to put the full path.

Use

  • either os.path.expanduser('~/Documents/MY_PROJECT/.env')

  • or: load_dotenv('/home/MY_USER/Documents/MY_PROJECT/.env')

and it will work.

Or you change your current working directory in your code editor to where the ".env" file is (which should be the project folder).

Or you open the project folder in the menu of your code editor, this should make the project folder the current working directory.

On Linux, you can also go to the project folder in the terminal and start the code editor from there, type for example codium or whatever you use in the command prompt.

Background

Quote from the other answer

Since, I moved my .env file's inside another subfolder config, then I had to provide the full path to load_dotenv() to make it work.

This gave me the idea of checking the working directory.

Current working directory

os.getcwd() gave me a folder further up the tree. And then I copied the ".env" file into that working directory and it worked.

Changing the working directory depends on your code editor. I use codium, which is the open source version of vscode, then you may follow for example Python in VSCode: Set working directory to python file's path everytime

Full path

You can also put the full path.

Funny enough, I had checked that before coming here, but I copied the path that you get from the terminal, starting with '~/Documents/MY_PROJECT, which does not find the file but does not alert either, any tried environment variables were just empty - just because the ".env" file itself was never read.

Bucephalus answered 20/1, 2022 at 19:49 Comment(0)
D
4

I had same error trying to load my environment configuration on ubuntu 20.04 and python-dotenv 0.15.0. I was able to rectify this using python interpreter which will log out any error encountered while trying to load your environments. Whenever your environment variable is loaded successfully, load_dotenv() returns True.

For me it was an issue with my configuration file (syntax error) that broke the loading process. All i needed to do was to go to my environment variable config file and fix the broken syntax..

Try passing verbose=True when loading your environment variable (from python's interpreter) to get more info from load_dotenv.

Dann answered 27/1, 2021 at 10:19 Comment(0)
L
3

I had:

variable = 'variable'

changing them to be:

variable=variable

fixed the issue. (removing spaces, remove '')

Lietman answered 5/12, 2022 at 10:32 Comment(0)
R
1

So this took me a while. My load_dotenv() was returning True.

I had commas after some records which is not correct.

Once I removed the commas the variables were working.

Recurrent answered 31/5, 2021 at 2:50 Comment(0)
M
0

I changed the key=value instead of key='value' and it worked for me.

>>> from dotenv import load_dotenv, find_dotenv
>>> load_dotenv(find_dotenv())
True

Documentation of dotenv library can be accessed from here: python_dotenv python package website

Monomorphic answered 10/5, 2024 at 19:47 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Remora
B
0

For me I had to use find_dotenv(usecwd=True) to get things to work. Looking at the source code for find_dotenv, by default it looks at the call stack until it finds a frame whose filename is different from the current script's filename and exists on disk as the starting point. In my case, I was running things as part of a snakemake workflow. I'm not sure why calling this function in a snakemake workflow was throwing things off, but adding the usecwd=True gives me the desired behavior.

So in summary, I'm using the following.

dotenv.load_dotenv(dotenv.find_dotenv(usecwd=True))
Bastion answered 2/8, 2024 at 19:4 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.