apache/superset · error · SSHTunnelingNotEnabledError

SSH Tunneling is not enabled

Error message

SSH Tunneling is not enabled

What it means

SSHTunnelingNotEnabledError raised by DatabaseDAO.create when attributes contain an 'ssh_tunnel' block but the FEATURE_FLAGS['SSH_TUNNELING'] feature flag is disabled. The database row is created first (super().create) and the tunnel attribute is only then rejected, so the tunnel is silently absent while the error surfaces.

Source

Thrown at superset/daos/database.py:73

    @classmethod
    def create(
        cls,
        item: Database | None = None,
        attributes: dict[str, Any] | None = None,
    ) -> Database:
        """
        Create a new database, with an optional SSH tunnel.
        """
        ssh_tunnel_attributes = (
            attributes.pop("ssh_tunnel", None) if attributes else None
        )

        database = super().create(item, attributes)

        if ssh_tunnel_attributes:
            if not is_feature_enabled("SSH_TUNNELING"):
                raise SSHTunnelingNotEnabledError()

            database.ssh_tunnel = SSHTunnel(**ssh_tunnel_attributes)

        return database

    @classmethod
    def find_by_id(
        cls,
        model_id: str | int,
        skip_base_filter: bool = False,
        id_column: str | None = None,
        query_options: list[Any] | None = None,
        *,
        skip_visibility_filter: bool = False,
    ) -> Database | None:
        """
        Find a database by id, eagerly loading the SSH tunnel relationship.
        """

View on GitHub (pinned to f4587218dd)

Solutions

  1. Enable the flag in superset_config.py: FEATURE_FLAG = {"SSH_TUNNELING": True} (also ensure sshtunnel Python deps are installed), then restart and re-send the ssh_tunnel attributes.
  2. Or drop the ssh_tunnel block and connect directly.
  3. If the database row was already created without a tunnel, update it with the tunnel after enabling the flag.

Example fix

# before (superset_config.py)
FEATURE_FLAG = {}

# after
FEATURE_FLAG = {
    "SSH_TUNNELING": True,
}
Defensive patterns

Strategy: validation

Validate before calling

from superset.extensions import feature_flag_manager

def tunneling_enabled() -> bool:
    from superset.utils.feature_flag_manager import is_feature_enabled
    return bool(is_feature_enabled("SSH_TUNNELING"))

Type guard

def payload_allows_tunnel(payload: dict) -> bool:
    return "ssh_tunnel" not in (payload or {}) or is_feature_enabled("SSH_TUNNELING")

Try / catch

try:
    DatabaseDAO.create(item, attributes)
except SSHTunnelingNotEnabledError:
    # config defect, not transient: enable flag or drop the tunnel block
    raise

Prevention

When it happens

Trigger: POST /api/v1/database/ with payload including ssh_tunnel parameters while config FEATURE_FLAG['SSH_TUNNELING'] is unset/False (default off).

Common situations: Environments where the flag was never turned on in superset_config.py; fresh installs assuming tunnel support is on by default; CI configs copying a minimal config that drops feature flags.

Related errors


AI-assisted analysis of apache/superset@f4587218dd (2026-08-14). Data as JSON: /api/errors/4441358e734fba47. Report an issue: GitHub.