django/django · critical · ImproperlyConfigured

Unable to load the SpatiaLite library extension as specified

Error message

Unable to load the SpatiaLite library extension as specified in your SPATIALITE_LIBRARY_PATH setting.

What it means

Raised as ImproperlyConfigured when SPATIALITE_LIBRARY_PATH is set in settings but conn.load_extension(path) raises for that exact path. The setting is treated as authoritative, so a failure on it is fatal rather than falling through to auto-detection. It means the file is missing, not loadable, or the wrong arch.

Source

Thrown at django/contrib/gis/db/backends/spatialite/base.py:56

        super().__init__(*args, **kwargs)

    def get_new_connection(self, conn_params):
        conn = super().get_new_connection(conn_params)
        # Enabling extension loading on the SQLite connection.
        try:
            conn.enable_load_extension(True)
        except AttributeError:
            raise ImproperlyConfigured(
                "SpatiaLite requires SQLite to be configured to allow "
                "extension loading."
            )
        # Load the SpatiaLite library extension on the connection.
        for path in self.lib_spatialite_paths:
            try:
                conn.load_extension(path)
            except Exception:
                if getattr(settings, "SPATIALITE_LIBRARY_PATH", None):
                    raise ImproperlyConfigured(
                        "Unable to load the SpatiaLite library extension "
                        "as specified in your SPATIALITE_LIBRARY_PATH setting."
                    )
                continue
            else:
                break
        else:
            raise ImproperlyConfigured(
                "Unable to load the SpatiaLite library extension. "
                "Library names tried: %s" % ", ".join(self.lib_spatialite_paths)
            )
        return conn

    def prepare_database(self):
        super().prepare_database()
        # Check if spatial metadata have been initialized in the database
        with self.cursor() as cursor:
            cursor.execute("PRAGMA table_info(geometry_columns);")

View on GitHub (pinned to ae25a40be0)

Solutions

  1. Verify the file exists at the configured path and that `python -c "import ctypes; ctypes.CDLL('/that/path')"` loads it.
  2. Point SPATIALITE_LIBRARY_PATH at mod_spatialite.so (the loadable SQLite module) rather than the plain libspatialite shared library.
  3. Remove the setting entirely and let Django auto-detect via find_library('spatialite') / mod_spatialite.
  4. Reinstall libspatialite/mod_spatialite matching your SQLite/SQLite-extension-loading build.

Example fix

# before (wrong library target)
SPATIALITE_LIBRARY_PATH = '/usr/lib/libspatialite.so.7'
# after (loadable extension module)
SPATIALITE_LIBRARY_PATH = '/usr/lib/mod_spatialite.so'
# or: omit the setting and let Django auto-detect
Defensive patterns

Strategy: validation

Validate before calling

import ctypes, os
from django.conf import settings
path = getattr(settings, 'SPATIALITE_LIBRARY_PATH', None)
if path:
    assert os.path.exists(path), f'SPATIALITE_LIBRARY_PATH missing: {path}'
    ctypes.CDLL(path)  # raises if not loadable / wrong arch
    print('OK:', path)

Type guard

import os
from django.conf import settings

def spatialite_library_loads() -> bool:
    import ctypes
    p = getattr(settings, 'SPATIALITE_LIBRARY_PATH', None)
    return bool(p and os.path.exists(p) and _try_cdll(p))

def _try_cdll(p):
    try:
        ctypes.CDLL(p); return True
    except OSError:
        return False

Prevention

When it happens

Trigger: First connection under ENGINE=spatialite with SPATIALITE_LIBRARY_PATH defined; get_new_connection loops over lib_spatialite_paths at base.py:51, the first entry (the setting) fails load_extension, and the check at base.py:55 raises.

Common situations: Path points to a non-existent .so/.dylib; pointing to libspatialite.so.7 when mod_spatialite.so is required; wrong architecture (arm64 vs x86_64) after a CPU migration; SPATIALITE_LIBRARY_PATH copied from a tutorial for a different OS.

Related errors


AI-assisted analysis of django/django@ae25a40be0 (2026-08-06). Data as JSON: /api/errors/58975a9704ed4b7b. Report an issue: GitHub.