Summary
api_key defaults to os.getenv("DEEPGRAM_API_KEY") directly in the __init__ signature, so Python evaluates it once, when the module is imported, not when the client is constructed. The idiomatic pattern (imports at the top of a file, load_dotenv() below them) therefore fails: the default is captured as None before the key is set, and DeepgramClient() raises even though DEEPGRAM_API_KEY is present by the time you instantiate.
Environment
- deepgram-sdk 7.3.1
- Python 3.14.6
- macOS (Darwin 24.6.0)
Root cause
deepgram/base_client.py (Fern-generated), BaseClient.__init__:
api_key: typing.Optional[str] = os.getenv("DEEPGRAM_API_KEY"), # evaluated at import
...
if api_key is None:
raise ApiError(body="The client must be instantiated be either passing in api_key or setting DEEPGRAM_API_KEY")
os.getenv(...) as a default argument runs once, at function-definition (import) time, not per call.
Reproduction
import os
os.environ.pop("DEEPGRAM_API_KEY", None) # not set in the shell at process start
from deepgram import DeepgramClient # default captured as None HERE
os.environ["DEEPGRAM_API_KEY"] = "dummy-key" # set afterward (what load_dotenv() does)
DeepgramClient() # raises, despite the var being set
Output on 7.3.1:
set at instantiation: True
DeepgramClient() -> ApiError: ... The client must be instantiated be either passing in api_key or setting DEEPGRAM_API_KEY
DeepgramClient(api_key=...) -> constructed OK
Impact
The documented zero-config pattern (DeepgramClient() reading DEEPGRAM_API_KEY) only works if the variable is in the OS environment before the deepgram import runs. With python-dotenv (very common), load_dotenv() runs after the import, so the key is invisible. The error message ("set DEEPGRAM_API_KEY") is misleading because the variable is already set, which sends you to debug the wrong thing.
Suggested fix
Default the parameter to None and resolve the env var inside __init__ so it's read at call time:
def __init__(self, *, api_key: typing.Optional[str] = None, ...):
if api_key is None:
api_key = os.getenv("DEEPGRAM_API_KEY")
if api_key is None:
raise ApiError(body="The client must be instantiated by either passing in api_key or setting DEEPGRAM_API_KEY")
(Also worth fixing the grammar in the error string: "must be instantiated be either" -> "by either".) Since base_client.py is Fern-generated, the change belongs in the generator template.
Workaround
Pass the key explicitly, DeepgramClient(api_key=os.getenv("DEEPGRAM_API_KEY")), or call load_dotenv() before importing deepgram.
Summary
api_keydefaults toos.getenv("DEEPGRAM_API_KEY")directly in the__init__signature, so Python evaluates it once, when the module is imported, not when the client is constructed. The idiomatic pattern (imports at the top of a file,load_dotenv()below them) therefore fails: the default is captured asNonebefore the key is set, andDeepgramClient()raises even thoughDEEPGRAM_API_KEYis present by the time you instantiate.Environment
Root cause
deepgram/base_client.py(Fern-generated),BaseClient.__init__:os.getenv(...)as a default argument runs once, at function-definition (import) time, not per call.Reproduction
Output on 7.3.1:
Impact
The documented zero-config pattern (
DeepgramClient()readingDEEPGRAM_API_KEY) only works if the variable is in the OS environment before thedeepgramimport runs. Withpython-dotenv(very common),load_dotenv()runs after the import, so the key is invisible. The error message ("set DEEPGRAM_API_KEY") is misleading because the variable is already set, which sends you to debug the wrong thing.Suggested fix
Default the parameter to
Noneand resolve the env var inside__init__so it's read at call time:(Also worth fixing the grammar in the error string: "must be instantiated be either" -> "by either".) Since
base_client.pyis Fern-generated, the change belongs in the generator template.Workaround
Pass the key explicitly,
DeepgramClient(api_key=os.getenv("DEEPGRAM_API_KEY")), or callload_dotenv()before importingdeepgram.