HumanSignal/label-studio · error · ImproperlyConfigured

SECURE_PROXY_SSL_HEADER must be configured as "<header>,<val

Error message

SECURE_PROXY_SSL_HEADER must be configured as "<header>,<value>", for example "HTTP_X_FORWARDED_PROTO,https".

What it means

_get_secure_proxy_ssl_header parses the SECURE_PROXY_SSL_HEADER env var, which must contain exactly two comma-separated non-empty parts (header name and value), mirroring Django's setting of the same name. If splitting on ',' doesn't yield two non-empty strings, ImproperlyConfigured is raised; if unset/empty it returns None.

Source

Thrown at label_studio/core/settings/base.py:132

FRONTEND_HMR = get_bool_env('FRONTEND_HMR', False)
FRONTEND_HOSTNAME = get_env('FRONTEND_HOSTNAME', 'http://localhost:8010' if FRONTEND_HMR else HOSTNAME)

DOMAIN_FROM_REQUEST = get_bool_env('DOMAIN_FROM_REQUEST', False)

if DOMAIN_FROM_REQUEST:
    # in this mode HOSTNAME can be only subpath
    if HOSTNAME and not HOSTNAME.startswith('/'):
        raise ImproperlyConfigured('LABEL_STUDIO_HOST must be a subpath if DOMAIN_FROM_REQUEST is True')


def _get_secure_proxy_ssl_header():
    value = get_env('SECURE_PROXY_SSL_HEADER')
    if not value:
        return None

    parts = [part.strip() for part in value.split(',')]
    if len(parts) != 2 or not all(parts):
        raise ImproperlyConfigured(
            'SECURE_PROXY_SSL_HEADER must be configured as "<header>,<value>", '
            'for example "HTTP_X_FORWARDED_PROTO,https".'
        )
    return tuple(parts)


SECURE_PROXY_SSL_HEADER = _get_secure_proxy_ssl_header()
USE_X_FORWARDED_HOST = get_bool_env('USE_X_FORWARDED_HOST', False)
USE_X_FORWARDED_PORT = get_bool_env('USE_X_FORWARDED_PORT', False)

INTERNAL_PORT = '8080'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = get_bool_env('DEBUG', True)
DEBUG_MODAL_EXCEPTIONS = get_bool_env('DEBUG_MODAL_EXCEPTIONS', True)

# Whether to verify SSL certs when making external requests, eg in the uploader
# ⚠️ Turning this off means assuming risk. ⚠️

View on GitHub (pinned to 0b49e9b539)

Solutions

  1. Format the env var as exactly "<header>,<value>", e.g. SECURE_PROXY_SSL_HEADER=HTTP_X_FORWARDED_PROTO,https.
  2. Avoid extra quotes around the whole value; keep a single comma with both parts non-empty (whitespace is stripped).
  3. If you don't need it, unset the variable — the function returns None.
  4. If your proxy needs multiple headers, Django's format only supports one pair; pick the relevant header.

Example fix

// before
SECURE_PROXY_SSL_HEADER="HTTP_X_FORWARDED_PROTO"
// after
SECURE_PROXY_SSL_HEADER=HTTP_X_FORWARDED_PROTO,https
Defensive patterns

Strategy: validation

Validate before calling

import os, re
v = os.environ.get('SECURE_PROXY_SSL_HEADER')
if v:
    parts = [p.strip() for p in v.split(',')]
    if len(parts) != 2 or not all(parts):
        raise SystemExit('SECURE_PROXY_SSL_HEADER must be "<header>,<value>" e.g. HTTP_X_FORWARDED_PROTO,https')

Try / catch

try:
    from django.core.handlers.wsgi import WSGIHandler  # settings load
except ImproperlyConfigured as e:
    if 'SECURE_PROXY_SSL_HEADER' in str(e):
        logger.error('Fix SECURE_PROXY_SSL_HEADER env: %s', e)
    raise

Prevention

When it happens

Trigger: Setting SECURE_PROXY_SSL_HEADER to a value without exactly two non-empty comma-separated parts — e.g. 'HTTP_X_FORWARDED_PROTO' (one part), 'HTTP_X_FORWARDED_PROTO,' (empty part), or 'a,b,c' (three parts).

Common situations: Copying Django's tuple syntax ("HTTP_X_FORWARDED_PROTO", "https") verbatim including quotes into a single env var; shell stripping; forgetting the value half; using colons or semicolons instead of a comma.

Related errors


AI-assisted analysis of HumanSignal/label-studio@0b49e9b539 (2026-08-29). Data as JSON: /api/errors/1b93ea8f322afc89. Report an issue: GitHub.