dgraph-io/dgraph · error

Require a polygon for intersects query

Error message

Require a polygon for intersects query

What it means

Thrown by queryTokensGeo when an intersects query is issued without polygon loops. Intersects queries build tokens from both parents and cover of the provided polygon; with no loops, neither side of the index scan can be constructed.

Source

Thrown at types/geofilter.go:201

		// For a contains query, we only need to look at the objects whose cover matches our
		// parents. So we take our parents and prefix with the coverPrefix to look in the index.
		return createTokens(parents, coverPrefix), &GeoQueryData{pt: pt, loops: loops, qtype: qt}, nil

	case QueryTypeNear:
		if pt == nil {
			return []string{}, nil, errors.Errorf("Require a point for a within query.")
		}
		// A near query is the same as the intersects query. We form a loop with the given point and
		// the radius and then see what all does it intersect with.
		toks := parentCoverTokens(parents, cover)
		return toks, &GeoQueryData{loops: loops, qtype: QueryTypeIntersects}, nil

	case QueryTypeIntersects:
		// An intersects query is as the name suggests all the entities which intersect with the
		// given region. So we look at all the objects whose parents match our cover as well as
		// all the objects whose cover matches our parents.
		if len(loops) == 0 {
			return nil, nil, errors.Errorf("Require a polygon for intersects query")
		}
		toks := parentCoverTokens(parents, cover)
		return toks, &GeoQueryData{loops: loops, qtype: qt}, nil

	default:
		return nil, nil, errors.Errorf("Unknown query type")
	}
}

// MatchesFilter applies the query filter to a geo value
func (q GeoQueryData) MatchesFilter(g geom.T) bool {
	switch q.qtype {
	case QueryTypeWithin:
		return q.isWithin(g)
	case QueryTypeContains:
		return q.contains(g)
	case QueryTypeIntersects:
		return q.intersects(g)

View on GitHub (pinned to 759e242be6)

Solutions

  1. Provide a valid GeoJSON polygon (closed ring) for the intersects query
  2. Validate that the polygon parses into non-empty loops before issuing the query
  3. If intersecting with a point, use QueryTypeNear instead

Example fix

// before
{"type":"intersects"} // no polygon
// after
{"type":"intersects","coordinates":[[[0,0],[0,5],[5,5],[5,0],[0,0]]]}
Defensive patterns

Strategy: validation

Validate before calling

if qt == QueryTypeIntersects && len(loops) == 0 {
    return errors.New("intersects query requires a non-empty polygon")
}

Type guard

func hasLoops(loops []s2.Loop) bool { return len(loops) > 0 }

Try / catch

toks, data, err := types.GetGeoTokens(qt, pt, loops, cover, parents)
if err != nil && strings.Contains(err.Error(), "Require a polygon for intersects query") {
    // return a validation error to the caller
}

Prevention

When it happens

Trigger: Calling GetGeoTokens/queryTokens with QueryTypeIntersects and an empty/missing polygon (len(loops) == 0), e.g. an intersects filter whose GeoJSON polygon failed to parse or was omitted.

Common situations: GeoJSON polygon stripped by a serializer, a user passing a point or linestring where a polygon is required, or an earlier decode error silently producing zero loops.

Related errors


AI-assisted analysis of dgraph-io/dgraph@759e242be6 (2026-09-01). Data as JSON: /api/errors/79f6cf6cf194e775. Report an issue: GitHub.