Cómo corregir errores de .env en Python con python-dotenv

Publicado el: 12/07/2026
Tempo de leitura: 4 minutos
Como resolver erros com variáveis de ambiente usando python-dotenv

Los archivos .env permiten separar configuraciones y secretos del código fuente. Son útiles para claves de API, URLs de bases de datos, puertos y modos de ejecución. Sin embargo, es común que una variable devuelva None, que el archivo no se encuentre, que se cargue desde otra carpeta o que un valor del sistema tenga prioridad sobre el archivo. Resolver estos problemas exige comprender cómo se localiza y carga la configuración.

Antes de continuar, consulta la guía para leer variables de entorno de forma segura, el artículo sobre pathlib, la explicación de try y except, la guía de logging y el tutorial de entornos virtuales.

Las fuentes externas principales son la documentación oficial de python-dotenv y la documentación oficial de os.environ.

Instalar python-dotenv en el entorno correcto

python -m pip install python-dotenv
python -m pip show python-dotenv

Si el import falla, verifica el intérprete activo:

import sys
print(sys.executable)

Un error habitual es instalar el paquete globalmente y ejecutar el proyecto desde otro entorno virtual.

Crear el archivo .env

APP_ENV=development
DEBUG=false
PORT=8000
API_KEY=valor_de_ejemplo

No añadas espacios innecesarios alrededor del nombre. Los valores pueden ir entre comillas cuando contienen espacios o caracteres especiales. Evita escribir comentarios al final de un secreto si no estás seguro de cómo será interpretado.

Cargar variables básicas

import os
from dotenv import load_dotenv

load_dotenv()

entorno = os.getenv("APP_ENV")
puerto = os.getenv("PORT")
print(entorno, puerto)

os.getenv() devuelve strings o None. No convierte automáticamente números ni booleanos.

Por qué os.getenv devuelve None

Las causas más comunes son un nombre diferente, archivo en otra carpeta, proceso iniciado desde otro directorio, llamada a load_dotenv() demasiado tarde o archivo guardado como .env.txt. Imprime únicamente información no sensible:

from pathlib import Path

print("Directorio actual:", Path.cwd())
print("Existe .env:", Path(".env").is_file())
print("APP_ENV definida:", os.getenv("APP_ENV") is not None)

Nunca imprimas el valor de una clave real para depurar.

Usar una ruta explícita

from pathlib import Path
from dotenv import load_dotenv

BASE_DIR = Path(__file__).resolve().parent
RUTA_ENV = BASE_DIR / ".env"

load_dotenv(RUTA_ENV)

Este patrón no depende del directorio desde el que se ejecuta el comando. En proyectos con carpeta src, puede ser necesario utilizar parent para llegar a la raíz.

Localizar el archivo con find_dotenv

from dotenv import find_dotenv, load_dotenv

ruta = find_dotenv()
if not ruta:
    raise FileNotFoundError("No se encontró el archivo .env")

load_dotenv(ruta)

find_dotenv() busca en directorios superiores. Es útil, pero una ruta explícita suele ser más predecible en servicios y tareas programadas.

Entender la prioridad de valores

load_dotenv(override=False)

Por defecto, una variable ya definida en el entorno del proceso suele conservarse. Esto permite que producción configure valores reales sin ser reemplazada por un archivo local. Para pruebas controladas puedes utilizar:

load_dotenv(RUTA_ENV, override=True)

No actives override=True sin analizar, porque podría sustituir secretos o configuraciones proporcionadas por el sistema.

Convertir booleanos correctamente

def leer_booleano(nombre, predeterminado=False):
    valor = os.getenv(nombre)
    if valor is None:
        return predeterminado

    normalizado = valor.strip().casefold()
    verdaderos = {"1", "true", "yes", "si", "sí", "on"}
    falsos = {"0", "false", "no", "off"}

    if normalizado in verdaderos:
        return True
    if normalizado in falsos:
        return False
    raise ValueError(f"{nombre} no es un booleano válido")

bool("false") devuelve True porque cualquier string no vacío es verdadero. Por eso debes interpretar el texto explícitamente.

Convertir enteros con límites

def leer_entero(nombre, predeterminado=None, minimo=None, maximo=None):
    texto = os.getenv(nombre)
    if texto is None:
        if predeterminado is None:
            raise RuntimeError(f"Falta {nombre}")
        return predeterminado

    try:
        valor = int(texto)
    except ValueError as error:
        raise ValueError(f"{nombre} debe ser entero") from error

    if minimo is not None and valor < minimo:
        raise ValueError(f"{nombre} debe ser al menos {minimo}")
    if maximo is not None and valor > maximo:
        raise ValueError(f"{nombre} no puede superar {maximo}")
    return valor

Exigir variables obligatorias

def requerida(nombre):
    valor = os.getenv(nombre)
    if valor is None or not valor.strip():
        raise RuntimeError(f"Falta la variable obligatoria {nombre}")
    return valor


API_KEY = requerida("API_KEY")

El programa debe fallar al iniciar con un mensaje claro, en lugar de descubrir la ausencia durante una solicitud importante.

No incluir .env en Git

# .gitignore
.env
.env.*
!.env.example

Crea un archivo .env.example sin secretos:

APP_ENV=development
DEBUG=false
PORT=8000
API_KEY=

Este ejemplo documenta las variables necesarias. Si un secreto ya fue publicado, eliminarlo del repositorio no es suficiente: debes revocarlo y generar uno nuevo.

Evitar secretos en logs

import logging

logging.info("Configuración cargada")
logging.info("API_KEY definida: %s", API_KEY is not None)

No registres diccionarios completos de entorno, URLs con credenciales ni encabezados de autenticación.

Usar dotenv_values sin modificar el entorno

from dotenv import dotenv_values

config_archivo = dotenv_values(RUTA_ENV)
print(config_archivo.get("APP_ENV"))

dotenv_values() devuelve un diccionario. Es útil para inspección, pruebas y combinación explícita de capas:

config = {
    **dotenv_values(".env.shared"),
    **dotenv_values(".env.local"),
    **os.environ,
}

La última capa tiene prioridad. Documenta este orden para evitar sorpresas.

Separar configuraciones por entorno

Puedes mantener archivos de ejemplo o desarrollo, pero los secretos de producción deberían administrarse mediante el sistema de despliegue o un gestor de secretos. No copies automáticamente un archivo local a un servidor.

Problemas con IDEs y tareas programadas

VS Code, PyCharm, cron y Task Scheduler pueden iniciar el programa desde directorios distintos. Una ruta basada en __file__ evita depender de la carpeta de trabajo. También verifica qué usuario ejecuta el proceso y qué variables tiene disponibles.

Probar la configuración

def cargar_configuracion():
    return {
        "entorno": os.getenv("APP_ENV", "development"),
        "debug": leer_booleano("DEBUG", False),
        "puerto": leer_entero("PORT", 8000, 1, 65535),
        "api_key": requerida("API_KEY"),
    }

En pruebas, utiliza variables ficticias y restaura el entorno después de cada caso. Nunca uses secretos reales en el conjunto de pruebas.

Errores frecuentes

Los fallos habituales son guardar el archivo como .env.txt, ejecutar desde otra carpeta, llamar load_dotenv() después de leer variables, convertir "false" con bool(), forzar override=True y subir secretos a Git. También es común imprimir el valor secreto durante el diagnóstico.

Conclusión

Los errores de .env se resuelven controlando ruta, orden de carga, nombres y conversiones. Utiliza una ubicación explícita, valida variables obligatorias y transforma números y booleanos con funciones seguras. Mantén secretos fuera del repositorio y de los logs. En producción, permite que el entorno del sistema tenga prioridad y utiliza un gestor de secretos cuando el proyecto lo requiera.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Como resolver UnicodeDecodeError em arquivos Python
    Resolución de Errores
    Foto de perfil de Leandro Hirt da Academify

    Cómo corregir UnicodeDecodeError en Python paso a paso

    Corrige UnicodeDecodeError identificando la codificación, usando UTF-8, CP1252 o utf-8-sig, validando detecciones y evitando pérdidas silenciosas.

    Ler mais

    Tempo de leitura: 5 minutos
    12/07/2026
    Como resolver loop infinito que nunca termina em Python
    Resolución de Errores
    Foto de perfil de Leandro Hirt da Academify

    Cómo corregir un bucle infinito en Python

    Identifica y corrige bucles infinitos en Python revisando condiciones, incrementos, continue, entrada, timeouts, límites y depuración con pdb.

    Ler mais

    Tempo de leitura: 5 minutos
    11/07/2026
    Como identificar e corrigir erros de sintaxe em Python
    Resolución de Errores
    Foto de perfil de Leandro Hirt da Academify

    Cómo corregir SyntaxError en Python paso a paso

    Corrige SyntaxError en Python revisando tracebacks, dos puntos, delimitadores, comillas, indentación, operadores, f-strings y versiones incompatibles.

    Ler mais

    Tempo de leitura: 6 minutos
    11/07/2026
    Erro Python not recognized no terminal do Windows
    Resolución de Errores
    Foto de perfil de Leandro Hirt da Academify

    Cómo corregir “Python no se reconoce” en Windows

    Corrige “Python no se reconoce” en Windows revisando instalación, PATH, Python Launcher, alias de Microsoft Store, VS Code y pip.

    Ler mais

    Tempo de leitura: 5 minutos
    11/07/2026
    Debug de código Python usando o módulo pdb
    Resolución de Errores
    Foto de perfil de Leandro Hirt da Academify

    Depurar Python con pdb: guía práctica para principiantes

    Aprende a depurar Python con pdb: breakpoint, next, step, pila de llamadas, condiciones, post mortem, variables y buenas prácticas.

    Ler mais

    Tempo de leitura: 5 minutos
    11/07/2026
    Como resolver erro PermissionError em Python rapidamente
    Resolución de Errores
    Foto de perfil de Leandro Hirt da Academify

    Cómo corregir PermissionError en Python paso a paso

    Corrige PermissionError en Python revisando rutas, carpetas protegidas, archivos bloqueados, permisos, servicios y manejo seguro de excepciones.

    Ler mais

    Tempo de leitura: 4 minutos
    11/07/2026