apache/superset · error · ImportFailedError

User doesn't have permission to create or update databases

Error message

User doesn't have permission to create or update databases

What it means

ImportFailedError ("User doesn't have permission to create or update databases") is raised by the legacy v0 dataset importer when the import bundle contains a `databases` section, a request user is present, and that user lacks the `can_write` permission on Database. The v0 path creates/updates the embedded database connections, so it mirrors the v1 import commands' requirement for database write access. When no user is present (CLI imports), the check is skipped.

Source

Thrown at superset/commands/dataset/importers/v0.py:227


def import_from_dict(data: dict[str, Any], sync: Optional[list[str]] = None) -> None:
    """Imports databases from dictionary"""
    if not sync:
        sync = []
    if isinstance(data, dict):
        databases = data.get(DATABASES_KEY, [])
        # This legacy path creates/updates the embedded database connections.
        # Mirror the versioned (v1) import commands and require database write
        # permission for the objects being created here. Only enforced when there
        # is something to import and a request user is present, so the CLI import
        # paths keep working.
        if (
            databases
            and get_user()
            and not security_manager.can_access("can_write", "Database")
        ):
            raise ImportFailedError(
                "User doesn't have permission to create or update databases"
            )
        logger.info("Importing %d %s", len(databases), DATABASES_KEY)
        for database in databases:
            db_obj = Database.import_from_dict(database, sync=sync)
            # ``import_from_dict`` sets fields via setattr, bypassing
            # ``set_sqlalchemy_uri``.  Call it explicitly so that any plaintext
            # password in the URI is extracted into the encrypted ``password``
            # column and replaced with the password mask in ``sqlalchemy_uri``.
            if db_obj is not None:
                # Only call set_sqlalchemy_uri when the imported URI carries a real
                # password (non-empty and not the password mask).  If the URI has no
                # password segment — common when users keep secrets out of YAML and
                # rely on the encrypted ``password`` column from a prior run —
                # calling set_sqlalchemy_uri would set ``password = None`` and break
                # existing connections.
                parsed = make_url_safe(db_obj.sqlalchemy_uri)
                if parsed.password and parsed.password != PASSWORD_MASK:

View on GitHub (pinned to f4587218dd)

Solutions

  1. Grant the importing user `can_write` on Database (or perform the import as Admin).
  2. Strip the `databases` section from the bundle so only datasets are imported — the databases must then already exist on the target.
  3. For automated flows, use the CLI import path, which runs without a request user and is not subject to this check.
Defensive patterns

Strategy: validation

Validate before calling

# Before a UI upload, check permission when the bundle carries databases
import yaml
from superset import security_manager
from flask_login import current_user

def v0_import_allowed(contents: dict) -> bool:
    carries_databases = any(
        isinstance(yaml.safe_load(c), dict) and "databases" in yaml.safe_load(c)
        for c in contents.values()
    )
    if not carries_databases:
        return True
    return security_manager.can_access("can_write", "Database")

Try / catch

from superset.commands.exceptions import ImportFailedError
try:
    ImportDatasetsCommand(contents, {})
except ImportFailedError as ex:
    if "permission to create or update databases" in str(ex):
        # either drop the databases section or escalate to an admin — retry unchanged is futile
        strip_databases_and_retry(contents) or escalate_to_admin()

Prevention

When it happens

Trigger: Uploading a legacy UI export (v0 format with DATABASES_KEY) to the dataset import endpoint as a non-admin without can_write on Database; a Gamma/Alpha user importing bundles that carry their own database definitions.

Common situations: Sharing legacy export files across teams; importing bundles produced by the old UI export into a deployment with stricter RBAC; service accounts without database-write grants used for imports.

Related errors


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