django/django · warning · DisallowedRasterLookup

Cannot use object {normalized!r} for a spatial lookup parame

Error message

Cannot use object {normalized!r} for a spatial lookup parameter. If this is a raster, wrap it with GDALRaster() before using it in a lookup to enable writing or fetching.

What it means

Raised by GDALRaster.check_raster_lookup_value (a classmethod invoked during ORM spatial lookups) when the lookup value, after preprocessing, is a dict or str. Dicts can force GDALRaster into write mode and strings can be interpreted as virtual-filesystem paths that fetch remote data, so Django refuses to coerce them automatically inside a lookup. The fix is to construct the GDALRaster explicitly before using it in the queryset filter. It raises DisallowedRasterLookup (subclass of SuspiciousOperation), not GDALException.

Source

Thrown at django/contrib/gis/gdal/raster/source.py:261

        if isinstance(ds_input, Path):
            ds_input = str(ds_input)
        return ds_input

    @classmethod
    def check_raster_lookup_value(cls, ds_input):
        """
        Raise DisallowedRasterLookup for values inappropriate in lookups:
        - No dicts, which GDALRaster(write=False) might still write to.
        - No strings or Paths, which might fetch over the virtual filesystem.
        """
        normalized = cls._preprocess_input(ds_input)
        if isinstance(normalized, (dict, str)):
            msg = (
                f"Cannot use object {normalized!r} for a spatial lookup "
                "parameter. If this is a raster, wrap it with GDALRaster() "
                "before using it in a lookup to enable writing or fetching."
            )
            raise DisallowedRasterLookup(msg)

    def _flush(self):
        """
        Flush all data from memory into the source file if it exists.
        The data that needs flushing are geotransforms, coordinate systems,
        nodata_values and pixel values. This function will be called
        automatically wherever it is needed.
        """
        # Raise an Exception if the value is being changed in read mode.
        if not self._write:
            raise GDALException(
                "Raster needs to be opened in write mode to change values."
            )
        capi.flush_ds(self._ptr)

    @property
    def vsi_buffer(self):
        if not (

View on GitHub (pinned to ae25a40be0)

Solutions

  1. Wrap the value: GDALRaster(the_dict_or_str) before passing it to the lookup
  2. If you only have dict/string input, build the GDALRaster once and reuse the instance in the filter
  3. Validate user-supplied raster parameters at the view boundary and reject raw dict/str before they reach the ORM

Example fix

// before
qs = RasterModel.objects.filter(rast__contains=json_dict)
// after
raster = GDALRaster(json_dict)
qs = RasterModel.objects.filter(rast__contains=raster)
Defensive patterns

Strategy: validation

Validate before calling

from django.contrib.gis.gdal.raster.source import GDALRaster

def coerce_raster_lookup(value):
    if isinstance(value, (dict, str)):
        return GDALRaster(value)
    return value

Type guard

def is_lookup_safe(value) -> bool:
    return not isinstance(value, (dict, str))

Try / catch

from django.contrib.gis.gdal.raster.source import DisallowedRasterLookup
try:
    qs = Model.objects.filter(rast__contains=raw)
except DisallowedRasterLookup:
    qs = Model.objects.filter(rast__contains=GDALRaster(raw))

Prevention

When it happens

Trigger: Using Model.objects.filter(geom__contains=some_dict) or filter(field__lookup='/vsicurl/http://...') where the right-hand side is a dict or a path-like string. Any GIS lookup (e.g. __intersects, __contains, __distance) receiving a raw dict/string describing a raster rather than a GDALRaster instance.

Common situations: Constructing raster lookup parameters dynamically and forgetting the GDALRaster() wrapper; passing a JSON dict straight from request data into a raster lookup; security hardening catching attempts to read remote VSI paths in a lookup.

Related errors


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