django/django · error · ValueError

Band indices are not allowed for this operator, it works on

Error message

Band indices are not allowed for this operator, it works on bbox only.

What it means

ValueError raised in PostGISOperator.check_raster() (line 57-61) when a left-hand-side band index is provided for a raster operator that has no func attribute — i.e., a bounding-box-only operator defined purely by an SQL op symbol (like ~, &&, @). These operators work on the raster's convex hull and cannot reference individual bands.

Source

Thrown at django/contrib/gis/db/backends/postgis/operations.py:58

    def as_sql(self, connection, lookup, template_params, *args):
        template_params = self.check_raster(lookup, template_params)
        template_params = self.check_geography(lookup, template_params)
        return super().as_sql(connection, lookup, template_params, *args)

    def check_raster(self, lookup, template_params):
        spheroid = lookup.rhs_params and lookup.rhs_params[-1] == "spheroid"

        # Check which input is a raster.
        lhs_is_raster = lookup.lhs.field.geom_type == "RASTER"
        rhs_is_raster = isinstance(lookup.rhs, GDALRaster)

        # Look for band indices and inject them if provided.
        if lookup.band_lhs is not None and lhs_is_raster:
            if not isinstance(lookup.band_lhs, int):
                name = lookup.band_lhs.__class__.__name__
                raise TypeError(f"Band index must be an integer, but got {name!r}.")
            if not self.func:
                raise ValueError(
                    "Band indices are not allowed for this operator, it works on bbox "
                    "only."
                )
            template_params["lhs"] = "%s, %s" % (
                template_params["lhs"],
                lookup.band_lhs,
            )

        if lookup.band_rhs is not None and rhs_is_raster:
            if not isinstance(lookup.band_rhs, int):
                name = lookup.band_rhs.__class__.__name__
                raise TypeError(f"Band index must be an integer, but got {name!r}.")
            if not self.func:
                raise ValueError(
                    "Band indices are not allowed for this operator, it works on bbox "
                    "only."
                )
            template_params["rhs"] = "%s, %s" % (

View on GitHub (pinned to ae25a40be0)

Solutions

  1. Remove the band index from bbox-only lookups (bbcontains, bboverlaps, contained, left, right, strictly_above, etc.).
  2. If band-level comparison is needed, switch to a func-based operator like contains, intersects, or within that supports band indices.
  3. Consult gis_operators in PostGISOperations to confirm which operators accept raster band indices.

Example fix

// before — bbox operator with band index
MyRasterModel.objects.filter(rast__bboverlaps=(other_rast, 1))
// ValueError: Band indices are not allowed for this operator, it works on bbox only.

// after — drop the band index for bbox operators
MyRasterModel.objects.filter(rast__bboverlaps=other_rast)
// or use a func-based operator that supports bands:
MyRasterModel.objects.filter(rast__contains=(other_rast, 1))
Defensive patterns

Strategy: validation

Validate before calling

from django.contrib.gis.db.backends.postgis.operations import PostGISOperations

BBOX_ONLY_OPS = {
    name for name, op in PostGISOperations.gis_operators.items()
    if not getattr(op, 'func', None)
}

def supports_band_index(lookup_name: str) -> bool:
    return lookup_name not in BBOX_ONLY_OPS

Type guard

def is_bbox_only_operator(lookup_name: str) -> bool:
    op = PostGISOperations.gis_operators.get(lookup_name)
    return op is not None and not getattr(op, 'func', None)

Try / catch

try:
    Model.objects.filter(rast__bboverlaps=(other, 1))
except ValueError:
    # bbox operator — drop the band index
    Model.objects.filter(rast__bboverlaps=other)

Prevention

When it happens

Trigger: Using a bbox operator with a band index: MyRasterModel.objects.filter(rast__bbcontains=(other_raster, 1)) or rast__bboverlaps=(other, 1), where the operator (bbcontains, bboverlaps, contained, overlaps_left, etc.) has no func and the tuple includes a band index on the LHS.

Common situations: Assuming all raster operators accept band indices; copy-pasting a band index from a contains/intersects lookup into a bboverlaps lookup.

Related errors


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