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
- Wrap the value: GDALRaster(the_dict_or_str) before passing it to the lookup
- If you only have dict/string input, build the GDALRaster once and reuse the instance in the filter
- 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
- Always wrap dict/str raster params in GDALRaster() before ORM lookups
- Treat DisallowedRasterLookup as a security signal - never silently coerce untrusted VSI paths
- Validate request-supplied raster descriptors at the view boundary
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
- Invalid data source input type: "{}".
- Raster needs to be opened in write mode to change values.
- Could not create a SpatialReference from input.
- Geotransform must consist of 6 numeric values.
- Transform only accepts SpatialReference, string, and integer
AI-assisted analysis of django/django@ae25a40be0 (2026-08-06).
Data as JSON: /api/errors/3f4adb3c8b143b0c.
Report an issue: GitHub.