2026, Jan 11 06:03

URL из .env в Python печатаются с \x3a: как добиться стабильности

Разбираем, почему URL из .env в Python выглядят как http\x3a//..., откуда берётся кодирование и как исправить проблему через python-dotenv с override=True.

Шестнадцатеричные последовательности в URL, попадающем из .env, способны сломать иначе простой процесс настройки. Особенно странно выглядит ситуация, когда одно и то же значение из .env то выводится как нормальный URL, то внезапно с подстановкой \x3a вместо двоеточий. Ниже — краткое объяснение, что происходит, и как добиваться стабильной загрузки переменных окружения в Python.

Воспроизводим странный URL из .env

Начните с простого значения в окружении:

GATEWAY_URL="http://localhost:9000"

Загрузим его в Python через python-dotenv и прочитаем через os.getenv. Даже дополнительный проход через unquote здесь не помогает:

import os
from urllib.parse import unquote
from dotenv import load_dotenv

load_dotenv()

service_host = os.getenv("GATEWAY_URL", "")
print(service_host)

service_host = unquote(os.getenv("GATEWAY_URL", ""))
print(service_host)

Оба вывода могут выглядеть так: http\x3a//localhost\x3a9000.

Теперь добавьте ещё одну запись:

NEXT_GATEWAY="http://localhost:9001"

Если прочитать её сразу после редактирования файла, можно получить привычный результат:

load_dotenv()

alt_host = os.getenv("NEXT_GATEWAY", "")
print(alt_host)

Вывод может быть таким: http://localhost:9001. Однако после перезапуска виртуального окружения всё «откатывается», и строка печатается как http\x3a//localhost\x3a9001. Речь не про «очистку» URL; важна именно несогласованность между тем, что записано в .env, и тем, что приходит в Python.

Что на самом деле происходит

Поведение непоследовательно, потому что значение, попадающее в Python, иногда оказывается заранее закодированным ещё до того, как python-dotenv прочитает ваш .env. Иными словами, в окружении уже может лежать изменённая версия переменной, и простой вызов os.getenv возвращает именно её. Замена кавычек или ручная «очистка» строки не отвечает на вопрос, почему некорректное содержимое вообще оказывается в окружении.

Правка, которая возвращает стабильность

На практике проблему решает принудительная перезапись существующих переменных окружения в python-dotenv. Это гарантирует, что значения из .env заменят всё, что могло быть подмешано ранее:

from dotenv import load_dotenv
import os

load_dotenv(override=True)
cloud_addr = os.getenv("SUPABASE_URL")
print(cloud_addr)

С установленным флагом override ранее искажённый URL вроде

https\3a//xxxxxxxxxxxxxxxxxx.supabase.co

печатается как

https://xxxxxxxxxxxxxxxxxx.supabase.co

Также было отмечено, что это поведение связано с недавно исправленной проблемой в VSCode; принудительный override возвращает работоспособность даже на затронутой конфигурации. Подробности: https://github.com/microsoft/vscode/issues/248468.

Почему это важно

Конфигурация через переменные окружения должна быть предсказуемой между платформами и сессиями. Если рантайм подхватывает уже изменённую переменную, сегодня вы видите рабочий URL, а после перезапуска — его шестнадцатерично закодированный вариант. Это ломает ожидания в CI/CD, локальной разработке и любой истории про воспроизводимые среды. Гарантируйте, что побеждает значение, загруженное из .env, — так вы избегаете тонких и затратных по времени отладок.

Итоги

Если URL из .env время от времени появляются с \x3a или \3a вместо двоеточий, загружайте окружение с включённой перезаписью. Это устраняет несогласованность из‑за предварительно заполненных значений или инъекций со стороны редактора и возвращает чистый, предсказуемый процесс конфигурации. Если вы используете VSCode, имейте в виду связанный баг; описанный обходной путь работает даже там, где он проявляется. Ставьте во главу угла авторитетность .env и проверяйте фактические значения при старте, чтобы сразу ловить любые расхождения.