All findings · Lucene finding · LFV-434 · xyshape-within-line-query-not-rejected

XYShape accepts a WITHIN query with a line geometry, which LatLonShape rejects, and silently returns only the points lying on the line

XYShape.newLineQuery(field, WITHIN, line) should throw, as LatLonShape does and as XYShape did up to 8.4.1, but since 8.5.0 it is accepted and silently returns only indexed points lying on the line. Of the line (0,0)-(10,0), a segment on it and the point (5,0), only the point matches.

Summary

Priority
Low, rank 406XYShape accepts WITHIN with a line query and silently returns only on-line points, but asking which shapes lie WITHIN a line is unusual.
Impact
wrong error
Since
8.5.0 (LUCENE-9194, 2020)introduced 2020-02-07 · about 6 years
Affected
8.5.0 to 10.6.0 and main (6 releases and main executed, the rest by a jar scan, 10.6.0 by reading)
Status
documented
Found by
static diff of the lat/lon and x/y sibling query classes, then a public-API test

AI-assisted page: this finding was first signalled by code reading or testing and then checked with AI tools; the checks it went through, and what each found, are under Prior reports, history and checks. Not yet triaged by a human. Snapshot of 2026-11-03.

The finding in 30 seconds

XYShape indexes a line as segments and a point as a point. A WITHIN query asks each indexed piece whether it lies within the query shape. For a query line Lucene can only answer that for points, so LatLonShape rejects WITHIN with a line, and XYShape did up to 8.4.1. Since 8.5.0 XYShape accepts it and answers partially.

Diagram of the bug: the WITHIN query with the line (0,0)-(10,0) is accepted by XYShape, while LatLonShape throws IllegalArgumentException for the same query. Of the three indexed shapes, the point (5,0) is tested with a point-on-line test and matches; the identical line (0,0)-(10,0) and the segment (2,0)-(4,0) are tested with Line2D.containsLine, which always returns false, so the search returns 1 of 3 shapes.
The query line (0,0)-(10,0) and the three indexed shapes: the point (5,0) passes the point-on-line test and matches; the identical line and the segment (2,0)-(4,0) go to Line2D.containsLine, which always returns false; LatLonShape rejects the same query. Select the still to open it at full size. Generated with AI, checked against the code.
  1. You index three cartesian shapes with XYShape: the line (0,0)-(10,0), the segment (2,0)-(4,0) that lies on it, and the point (5,0).
  2. You ask which shapes lie WITHIN that line: XYShape.newLineQuery("shape", QueryRelation.WITHIN, line (0,0)-(10,0)).
  3. You expect an IllegalArgumentException: LatLonShape rejects the same query ("does not support WITHIN queries with line geometries"), and XYShape itself did up to 8.4.1.
  4. You get no error and 1 hit of 3: the point (5,0). The identical line and the segment on it never match. A geometry array such as [polygon, line] is accepted too.
  5. Why: the XYShapeQuery constructor has no WITHIN + line check; the check was lost in 8.5.0 when the old XY line query was folded into it. Once accepted, a point is tested with a point-on-line test, a line segment with Line2D.containsLine, which always returns false.

Who is affected

Applications that index cartesian shapes with XYShape and build a WITHIN query with an XYLine, alone or in a geometry array, directly or through a query layer that passes any relation through. Default configuration, any index size, no error: on-line points come back, lines never. Query-time only; LatLonShape is not affected. Rare: no public report found since 2020.

Mechanism, terms and numbers712 words

LatLonShape.newLineQuery(field, QueryRelation.WITHIN, line) throws IllegalArgumentException ("LatLonShapeQuery does not support WITHIN queries with line geometries"), and so do LatLonPoint and LatLonDocValuesField; XYShape threw too, up to 8.4.1 ("XYShapeLineQuery does not support WITHIN queries"). Since 8.5.0, XYShape.newLineQuery(field, WITHIN, xyLine) and XYShape.newGeometryQuery(field, WITHIN, ...) with an XYLine anywhere in the array are accepted: LUCENE-9194 deleted XYShapeLineQuery and routed line queries to the generic XYShapeQuery, whose constructor adds no check of its own on the relation and the geometries. The accepted query then answers by shape type: an indexed point lying on the line matches (a point-on-line test), an indexed line segment never does, because Line2D.containsLine always returns false. For the line (0,0)-(10,0), the segment (2,0)-(4,0) on it and the point (5,0), the WITHIN query returns only the point. No error, any index size, the default configuration; 8.5.0 to 10.6.0 and main (six releases and main executed, the other 46 releases by a jar scan, 10.6.0 by reading). The fix restores the rejection with the same validateGeometries check that LatLonShapeQuery has.

Terms

  • XYShape: Lucene's field for cartesian (unitless x, y) shapes. XYShape.createIndexableFields indexes a polygon as triangles, a line as one segment per pair of consecutive vertices, and a point as a point. Its twin LatLonShape does the same for latitude/longitude.
  • WITHIN: a document matches when every indexed piece of its shape lies within the query geometry. With a query line, only points and collinear segments can lie within it.
  • Line2D: the query-side component built for a query line, shared by both twins.

Step 1: the query is built without a check

XYShape.newLineQuery (XYShape.java:219-225 at a9779ef3c193) calls newGeometryQuery (:261-272), which returns new XYShapeQuery(field, queryRelation, xyGeometries) for every relation (only CONTAINS with several geometries is split first). The constructor (XYShapeQuery.java:41-44) is just super(field, queryRelation, geometries);; the superclass (SpatialQuery.java:74-85) and XYGeometry.create (XYGeometry.java:24-44) reject only a null field or relation and null or empty geometry arrays, nothing looks at the combination of relation and geometry type. Its twin LatLonShapeQuery wraps the geometries in validateGeometries (LatLonShapeQuery.java:43-61), which throws for WITHIN with any Line in the array (excerpt; the message spans :54-56 in the source):

if (geometries != null && queryRelation == QueryRelation.WITHIN) {
  for (LatLonGeometry geometry : geometries) {
    if (geometry instanceof Line) {
      // TODO: line queries do not support within relations
      throw new IllegalArgumentException(
          "LatLonShapeQuery does not support " + QueryRelation.WITHIN + " queries with line geometries");

LatLonPointQuery.java:52-63 and LatLonDocValuesQuery.java:63-73 have the same rule and TODO, and LatLonPoint.newGeometryQuery documents it: "Line geometries are not supported for WITHIN relationship" (LatLonPoint.java:314-316).

Step 2: what the accepted query computes

The WITHIN leaf test (XYShapeQuery.java:108-144) checks each indexed piece against Line2D:

indexed piecetestresult for the query line (0,0)-(10,0)
point (5,0)contains(x, y) (:119) -> Line2D.java:84-90, point-on-line test (orient(...) == 0, no tolerance; EdgeTree.java:146-168)true: matches
segment (0,0)-(10,0), the identical linecontainsLine (:127) -> Line2D.java:142-154: // can be improved? return false;false: never matches
segment (2,0)-(4,0)the same containsLinefalse: never matches
triangle of a polygoncontainsTriangle (:137) -> Line2D.java:156-169: return false;false

For a query made only of lines, Line2D.relate (Line2D.java:92-104) never returns CELL_INSIDE_QUERY, so no index cell is accepted in bulk. The answer is essentially the point and multi-point documents whose points all lie on the query line (an indexed line whose vertices all coincide is decoded as a point and would match too): a subset of any reasonable WITHIN answer. In a mixed array such as [polygon, line] the polygon component answers as usual (ComponentTree.java), and only what lies on the line is under-matched.

The numbers

Line (0,0)-(10,0), segment (2,0)-(4,0) and point (5,0) indexed; XYShape.newLineQuery("shape", WITHIN, line (0,0)-(10,0)) matches 1 of 3: [point (5,0)]. XYShape.newGeometryQuery("shape", WITHIN, polygon, line) is accepted too; with a far-away polygon it returns only the point on the line. For an L-shaped query polyline (0,0)-(0,10)-(10,10), the independent reproducer's WITHIN query returns only the three indexed points on it and misses the identical polyline and the segments (0,2)-(0,8) and (3,10)-(7,10), while INTERSECTS on the same index returns exactly the 7 expected documents. LatLonShape, LatLonPoint and LatLonDocValuesField throw for the same input.

Exposure and likelihood226 words
  • Who. Applications that index cartesian shapes with XYShape (floor plans, CAD drawings, game maps, projected coordinates) and build a WITHIN query with an XYLine, alone or inside a geometry array such as [polygon, line], directly or through a downstream query layer. Two downstream engines' cartesian shape queries call XYShape.newGeometryQuery with the user's relation and geometry and no WITHIN + line check of their own (source reading, not executed); one of them rejects the same input on its geographic path with the comment "Line geometries and WITHIN relation is not supported by Lucene".
  • Default configuration. Public, non-experimental API, no special setting. The check is missing at query construction, so codec and index layout do not matter: the finder's test uses a plain new IndexWriterConfig(), this doc's repro Lucene's randomized test configuration.
  • Silent. No exception and no assertion, the same with assertions off, and the answer looks plausible because on-line points do come back.
  • Blast radius. Query-time only: that query's result. The index and other queries are unaffected. Any index size.
  • Not affected. LatLonShape, LatLonPoint and LatLonDocValuesField (they reject), and XYShape WITHIN queries whose geometries contain no XYLine (they never meet Line2D).
  • Rare in practice. "Which shapes lie within this line" is an unusual question; no public report was found since 8.5.0 (2020). The registry rates the likelihood "rare" and the priority low.

Minimal repro

The test shows that XYShape.newLineQuery(field, QueryRelation.WITHIN, line) accepts a WITHIN query with a line geometry (lost check since LUCENE-9194, 8.5.0).

TestXYShapeWithinLineRejected.java (JUnit test)32 lines
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.lucene.document;

import org.apache.lucene.document.ShapeField.QueryRelation;
import org.apache.lucene.geo.XYLine;
import org.apache.lucene.tests.util.LuceneTestCase;

public class TestXYShapeWithinLineRejected extends LuceneTestCase {

  public void testWithinLineQueryIsRejected() {
    XYLine line = new XYLine(new float[] {0, 10}, new float[] {0, 0});
    // expected: IllegalArgumentException (LatLonShape rejects WITHIN lines); actual: no exception
    expectThrows(
        IllegalArgumentException.class,
        () -> XYShape.newLineQuery("shape", QueryRelation.WITHIN, line));
  }
}
Command
# in a copy of this finding's repro folder (repro/LFV-434/, which holds src/)
# Lucene checkout at the tested commit, built with: ./gradlew --no-daemon assemble   (JDK 25)
LUCENE=/path/to/lucene; V=12.0.0-SNAPSHOT
CP=$LUCENE/lucene/core/build/libs/lucene-core-$V.jar
CP=$CP:$LUCENE/lucene/codecs/build/libs/lucene-codecs-$V.jar
CP=$CP:$LUCENE/lucene/test-framework/build/libs/lucene-test-framework-$V.jar
CP=$CP:randomizedtesting-runner-2.9.2.jar:junit-4.13.2.jar:hamcrest-3.0.jar   # test-framework dependencies (Maven Central)
CP=$CP:junit-platform-console-standalone-6.1.3.jar   # JUnit Platform console launcher (Maven Central)

javac -d classes -cp "$CP" $(find src -name '*.java')

# run 1: assertions on, seed DEADBEEF
java -ea -esa --add-modules jdk.incubator.vector --enable-native-access=ALL-UNNAMED -Dtests.seed=DEADBEEF \
     -cp "classes:$CP" org.junit.platform.console.ConsoleLauncher \
     execute --select-class org.apache.lucene.document.TestXYShapeWithinLineRejected
Expected vs actual
Expected IllegalArgumentException, as LatLonShape.newLineQuery throws and XYShape threw up to 8.4.1; actual: no exception (-ea and -da).

All files of this repro: repro/LFV-434/

More files, environment, full output37 words

Environment

luceneLucene main e1faeba08bde (2026-11-02)
jdk25.0.3+9-LTS

Observed output

# Lucene main 645d4fe14a20, assertions on (-ea), seed DEADBEEF: 1 test(s) run, 1 failed
    => junit.framework.AssertionFailedError: Expected exception IllegalArgumentException but no exception was thrown
       org.apache.lucene.tests.util.LuceneTestCaseParent.expectThrows(LuceneTestCaseParent.java:1432)
       org.apache.lucene.tests.util.LuceneTestCaseParent.expectThrows(LuceneTestCaseParent.java:1418)
       org.apache.lucene.document.TestXYShapeWithinLineRejected.testWithinLineQueryIsRejected(TestXYShapeWithinLineRejected.java:28)

Why it looks unintended

  • LatLonShape, LatLonPoint and LatLonDocValuesField reject WITHIN with a line ("TODO: line queries do not support within relations").
  • XYShape rejected it too up to 8.4.1; the 8.5.0 refactoring that dropped the check announced only an API simplification.
  • The accepted query contradicts itself: a point on the line is "within" it, the identical line is not.
The full argument228 words
  • The twin rejects it, with a TODO saying so. LatLonShapeQuery, LatLonPointQuery and LatLonDocValuesQuery all throw for WITHIN with a line, each with // TODO: line queries do not support within relations; LatLonPoint.newGeometryQuery documents "Line geometries are not supported for WITHIN relationship".
  • XY itself rejected it until 8.5.0. XYShapeLineQuery (LUCENE-8632, 2019) documented "QueryRelation.WITHIN queries are not yet supported" and threw "XYShapeLineQuery does not support WITHIN queries"; 8.2.0 and 8.4.1 throw when run.
  • The change that dropped it announced no behaviour change. LUCENE-9194's CHANGES entry: "Simplify XYShapeXQuery API by adding a new abstract class called XYGeometry. Queries are executed with input objects that extend such interface." Its PR has one approval and no word on WITHIN or lines. Eight days earlier LUCENE-9141, by the same author, folded the LatLon queries into LatLonShapeQuery and kept the check; LUCENE-9641 (2021, the same author) added the rejection to the new LatLonPointQuery and LatLonDocValuesQuery and rewrote XYShapeQuery in the same commit without adding it there. That the XY check was lost by accident is an inference from this record.
  • Inconsistent with itself. A point on the line counts as within it, the identical line does not.
  • Why tests never caught it. The shared random line-query test draws only from POINT_LINE_RELATIONS = {INTERSECTS, DISJOINT, CONTAINS}, so WITHIN with a line is never run; no upstream test asserts the LatLon rejection either.
The devil's-advocate check269 words

The strongest case for "works as designed": WITHIN with a query line is knowingly unsupported. Line2D.containsLine is a deliberate false ("can be improved?"), the random tests exclude WITHIN for line queries, the newLineQuery javadoc speaks of shapes that "intersect" a linestring, and XYShapeQuery is @lucene.internal. Line containment is conservative elsewhere too: CONTAINS with a line query never matches an indexed line on either twin, not even the identical one (executed: XY CONTAINS (0,0)-(10,0) returns only an enclosing square; LatLon CONTAINS on the identical indexed line counts 0, INTERSECTS 1).

Why it fails: all of that explains why the operation is unsupported, which argues for rejecting it, as LatLon does and XY did, not for accepting it silently. The "intersect" wording decides nothing: LatLonShape.newLineQuery has the same sentence and rejects WITHIN, and XYShape.newPolygonQuery has it and supports WITHIN; the XYShape class javadoc says newLineQuery matches shapes "that have some QueryRelation with a linestring". @lucene.internal covers the query class, not the public factories that build it. No record shows that accepting the query was deliberate, and no author has said either way: an accident is the likely reading of the history, not a proven one. Verdict: not intended, framed as the missing rejection. The executing checks (the independent reproducer, the devil's advocate, the adjudication) rated it real. The cross-model intended-lens reviewer rated the intended argument moderate and concluded that it "justifies rejection rather than the current accepted-but-incomplete behavior". The cross-model refute-lens reviewer recorded a formal "not real" with low confidence because it could not run any code (its notes call that procedural), and agrees on the root cause.

Suggested fix

Recommended Restore the rejection in XYShapeQuery, mirroring LatLonShapeQuery (one file)

Restore the rejection: give XYShapeQuery the same validateGeometries check as LatLonShapeQuery, throwing IllegalArgumentException for WITHIN with any XYLine. One file, +18/-1 lines; with it every geo and shape suite of lucene/core passes (587 tests including the repro, 0 failures). Queries accepted today, including [polygon, line] arrays, would start throwing, as on LatLon.

All options and trade-offs3 options · 787 words

One fix was applied in a scratch worktree at a9779ef3c193 and run through gradle (seed DEADBEEF); the alternatives were not run.

Restore the rejection in XYShapeQuery, mirroring LatLonShapeQuery (one file) (validated by the checks) (recommended)

In the XYShapeQuery constructor, pass the geometries through a validateGeometries method that throws IllegalArgumentException for WITHIN with any XYLine in the array, as LatLonShapeQuery does (+18/-1 lines including the XYLine import; the code below is the changed part of an unpublished file). Worth adding "Line geometries are not supported for WITHIN" to the XYShape.newLineQuery and newGeometryQuery javadoc, as LatLonPoint.newGeometryQuery has; that is not part of the validated diff.

  /** Creates a query that matches all indexed shapes to the provided polygons */
  XYShapeQuery(String field, QueryRelation queryRelation, XYGeometry... geometries) {
    super(field, queryRelation, validateGeometries(queryRelation, geometries));
  }

  private static XYGeometry[] validateGeometries(
      QueryRelation queryRelation, XYGeometry... geometries) {
    if (geometries != null && queryRelation == QueryRelation.WITHIN) {
      for (XYGeometry geometry : geometries) {
        if (geometry instanceof XYLine) {
          // line queries do not support within relations (same as LatLonShapeQuery)
          throw new IllegalArgumentException(
              "XYShapeQuery does not support "
                  + QueryRelation.WITHIN
                  + " queries with line geometries");
        }
      }
    }
    return geometries;
  }

Trade-offs

  • Behaviour change. Queries accepted today start throwing: XYShape.newLineQuery(f, WITHIN, ...) and newGeometryQuery(f, WITHIN, ...) with any XYLine in the array, including mixed arrays such as [polygon, line] whose polygon part answers correctly today. That is exactly LatLon's behaviour; it needs a CHANGES entry, and whether it also needs a MIGRATE note or goes to main only is the maintainers' call. Downstream engines that pass the relation through would get an IllegalArgumentException for cartesian WITHIN with a linestring, as for geo shapes.
  • Cost: one loop over the query geometries at construction; nothing at search time.
  • Scope: the check sits in XYShapeQuery only. XYShapeDocValuesQuery extends BaseShapeDocValuesQuery directly and would not get it, but no public API builds it with a line today: XYShape.newSlowDocValuesBoxQuery passes only an XYRectangle (XYShape.java:214-217) and ShapeDocValuesField.newGeometryQuery always throws (ShapeDocValuesField.java:89-95).

What the checks validated

  • Stock main a9779ef3c193 (scratch worktree, gradle, seed DEADBEEF): the repro fails 2 of 3 with assertions on and off; the closest suites, every XY shape class of lucene/core/document (TestXY*Shape*: 11 classes, BKD and doc-values), pass: 69 tests, 9 skipped, 0 failures.
  • With the fix: the repro passes 3 of 3 with assertions on and off; the same 11 classes pass (72 tests with the repro, 9 skipped, 0 failures); every geo and shape suite of lucene/core (the geo package, document *Shape*, TestXY* and TestLatLon*, search TestXY* and TestLatLon*; 54 classes with the repro) passes: 587 tests, 40 skipped, 0 failures.
  • Lint and format: ecjLintMain passes with the fix. The first run flagged the test file only (a javadoc line wrap and an unused catch parameter, now an assertion that the message names WITHIN); with the edited test ecjLintTest and checkGoogleJavaFormat pass, and the edited test passes 3 of 3 with the fix and fails 2 of 3 on stock, assertions on and off. The suite runs above used the test before that edit.
  • Classpath runner on the stock main jars: 3 run, 2 failed with assertions on and off; with the fix shadowed, 3 run, 0 failed.
  • fix.diff and fix-with-test.diff (the fix plus the test as a new file) pass git apply --check on a9779ef3c193 (the recorded tree still listed the test file as an intent-to-add entry; the independent fact check re-ran both on a clean tree: both apply).
  • Earlier hunt runs: the finder's shadow fix passes its own test and 8 upstream XY shape test classes (40 tests started: 33 passed, 7 aborted by test assumptions, 0 failed); the follow-up re-run passes the version-neutral and the finder's tests with the fix (3 run, 0 failed, assertions off).

Implement line containment in Line2D (not run)

Make Line2D.containsLine return true when the indexed segment lies on the query polyline, so that XY WITHIN with a line becomes a supported query.

Trade-offs

Larger and riskier: a segment can span several collinear pieces of the query polyline or of a multi-line query; Line2D is shared with LatLon, whose quantized coordinates may no longer lie exactly on the original line, so LatLon would likely keep rejecting and the twins would diverge on purpose; CONTAINS semantics for lines (conservative today) would deserve the same look; and it needs new random-test coverage.

Document only (keeps today's behaviour)

State in the XYShape javadoc that WITHIN with lines is unsupported.

Trade-offs

Compatibility-preserving, and a valid choice if the maintainers prefer to declare the combination unsupported without a behaviour change. It keeps the silent partial answer for every caller who does not read the javadoc, though, and does not restore the 8.4.1 rejection or parity with LatLon.

Downstream note

Downstream engines whose cartesian shape queries pass the relation and geometry through to XYShape inherit the silent partial answer; with the fix they get an IllegalArgumentException instead, as for geo shapes.

How it was found

A static diff of Lucene's lat/lon and x/y sibling classes showed that LatLonShapeQuery validates its geometries and XYShapeQuery does not. The git history showed that the XY check existed until LUCENE-9194, and a public-API test confirmed that the query is accepted and answers partially.

The method in full159 words

Method: non-formal static comparison of sibling implementations, in a hunt unit on twin families (2026-10-26, main ea57360912ed).

  • A token-level diff of 96 sibling class pairs (Float/Double, Int/Long, vector Float/Byte, LatLon/XY and others), normalised per family, listed members present in only one twin. In the geo family, LatLonShapeQuery.validateGeometries exists only on the LatLon side; a class-file scan for the same idiom agreed (present in LatLonShapeQuery, absent in XYShapeQuery).
  • The git history showed that XYShapeLineQuery rejected WITHIN until LUCENE-9194 deleted it, eight days after LUCENE-9141 kept the same check for LatLon.
  • A targeted public-API JUnit then showed the query accepted and returning only the on-line point. It was checked by an independent reproducer with its own test, an intended-behaviour devil's advocate with executed controls, reading-only reviews by a model from another family (OpenAI GPT-5.6), an adjudication, a history, prior-report and security follow-up with a 19-run version sweep, an audit, and this doc's gradle runs on a9779ef3c193.

Prior reports, history and checks

Prior reports

No prior report found (2026-10-26): three prior-report tool runs (58 queries over GitHub, JIRA, the mailing lists and downstream repositories), manual GitHub, JIRA and web searches, and the changed files of all 410 open PRs. The closest item is a downstream issue in which a Lucene committer confirms that WITHIN with lines is unsupported on the geo path.

Searches3 searches

Verdict new: no report was found, by anyone. Keyword search cannot prove absence: GitHub search does not index diffs or review comments repository-wide, some phrasings ran only once because of rate limiting, and private security reports are not visible.

What was searched, when, and what turned up
WhereWhenHowFound
apache/lucene issues, PRs and commits; downstream repositories; the JIRA archive; dev@, java-user@, issues@, commits@2026-10-26the hunt's prior-report tool, three runs (58 queries: class, method, symptom and phrase variants such as XYShapeLineQuery, LUCENE-9194, XYLine WITHIN, "line geometries" WITHIN, validateGeometries, containsLine), plus the finder's and the devil's advocate's runsno report; history items only (LUCENE-9194, LUCENE-9141, LUCENE-8632, LUCENE-8554, LUCENE-9273, LUCENE-9641) and other WITHIN bugs (#9782, #9680)
GitHub (apache/lucene-solr, two downstream engines, all of GitHub), JIRA, the web2026-10-2610 manual issue searches, 3 code searches, 5 JIRA text searches, 7 web queries; issue, review and line comments of 6 old lucene-solr PRs (#1224, #1170, #2155, #726, #1341, #2059)context only: elastic/elasticsearch#70648 (closed; a Lucene spatial committer: "line and within are not supported. The limitation comes from the Lucene implementation", geo path only); PR #1224 has no word on WITHIN
all 410 open apache/lucene PRs; upstream main and branch_10x2026-10-26changed-file lists; commit history of the filesno open PR touches XYShapeQuery.java, XYShape.java, Line2D.java or LatLonShapeQuery.java; XYShapeQuery.java last changed 2022-08-09

History

Introduced in 8.5.0 by LUCENE-9194 (73dbf6d0610, 2020-02-07), which deleted XYShapeLineQuery and its WITHIN check. Executed: 8.2.0 and 8.4.1 reject the query; 8.5.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main accept it; the other releases by a jar scan. Unchanged on upstream main.

Versions tested5 rows

Introduced by 73dbf6d0610 "LUCENE-9194: Simplify XYShapeXQuery API by adding a new abstract class called XYGeometry" (PR apache/lucene-solr#1224 by iverase, merged 2020-02-07; branch_8x 5c1f2ca22a7). It deleted XYShapeLineQuery, which documented WITHIN as "not yet supported" and threw, and routed XYShape.newLineQuery to XYShapeQuery, whose constructor has no such check. The commit itself was not built; the executed bracket is 8.4.1 (rejects) to 8.5.0 (accepts).

Around it: XYShape arrived in the sandbox in 8.2.0 (LUCENE-8632, with the check) and moved to core in 8.5.0 (LUCENE-8621), so XYShape has been affected for its whole time in core. LUCENE-9141 (2020-01-30) kept the check for LatLon; LUCENE-9273 (8.6.0) gave Line2D.containsLine its current return false with the same observable result; LUCENE-9641 (2021) added the rejection to LatLonPointQuery and LatLonDocValuesQuery. On upstream main 20ced71c1e6 (2026-10-27), branch_10x and branch_10_6 the constructor is unchanged.

Versions and branches executed, with results
Version or commitVerdictResult
main a9779ef3c193 affectedaccepted: this doc's repro fails 2 of 3 (gradle and the classpath runner, assertions on and off); passes 3 of 3 with the fix
10.0.0 to 10.5.2 (12 releases) affected10.0.0 and 10.5.2 executed: accepted, returns only the point on the line; the other 10 lack the rejection string in the jar scan (not run)
9.0.0 to 9.12.3 (21 releases) affected9.0.0 and 9.12.3 executed: the same; the other 19 lack the rejection string in the jar scan (not run)
8.5.0 to 8.11.4 (19 releases) first release 8.5.08.5.0 and 8.11.4 executed: the same; the other 17 lack the rejection string in the jar scan (not run)
8.2.0 to 8.4.1 (sandbox module) rejects the query8.2.0 and 8.4.1 executed: IllegalArgumentException "XYShapeLineQuery does not support WITHIN queries"; before 8.2.0 there is no XYShape

Independent checks

An independent reproducer and an intended-behaviour devil's advocate reproduced it with their own tests, controls passing; reading-only reviews by a model from another family (OpenAI GPT-5.6) agreed on the root cause; an adjudication and an audit re-ran it, and this doc's gradle runs reproduce it on a9779ef3c193 and validate the fix.

Checks and verdicts335 words

Every executing check wrote or re-ran a repro on stock main, and every control passed. The cross-model reviews could not execute code here, so all execution evidence comes from the hunt's own runs.

Each independent check and its verdict
CheckVerdictWhat it found
finder candidateTwin diff, then a public-API JUnit: fails on main (assertions on and off), 10.5.2, 9.12.3 and 8.5.0; 8.4.1 throws; deterministic over 10 iterations; the fix passes it and 8 upstream XY shape test classes (33 tests).
cross-model review, refute lens (OpenAI GPT-5.6, reading only) not real, low (procedural)Could not execute anything, and it votes not real without a run of its own; on substance the root cause agrees, inputs in contract, intended argument moderate. A separate re-run of the repro reproduced the failure.
independent reproducer realOwn test with an L-shaped polyline: no exception, WITHIN returns only the 3 on-line points; the INTERSECTS control is exact. Fails on main (assertions on and off), 10.5.2 and 9.12.3.
cross-model review, intended lens (the cross-model review, OpenAI GPT-5.6, reading only) real, mediumThe strongest "works as designed" case, rated moderate, justifies a rejection, not silent partial matching.
intended-behaviour devil's advocate real, framed as the missing rejectionExecuted controls: CONTAINS with a line never matches an indexed line on either twin, so "WITHIN must return the identical line" does not survive; the lost rejection does. Re-ran the finder's test on main and 10.5.2.
adjudication confirmed, highRe-ran the independent reproduction's test (assertions on and off) and the finder's; duplicate of none; class wrong error.
credibility audit and re-verification keepRe-ran both repros on main ea57360912ed; the re-verification on a9779ef3c193 still reproduces both.
this doc reproduced; fix validatedGradle in a scratch worktree at a9779ef3c193: the repro fails 2 of 3 (assertions on and off) and passes 3 of 3 with the fix; with the fix 587 geo and shape tests pass and the lint and format checks pass; the classpath runner agrees.

Diagram file

The diagram as a still image, generated with AI and checked against the code. It is under 10 MB, the limit for a GitHub attachment.

Sources and provenance

Finding record, Lucene and upstream sources, repro files and diagram notes1,444 words

Finding record

LFV-434, snapshot of 2026-11-03

Registry title
XYShape.newLineQuery / newGeometryQuery accept QueryRelation.WITHIN with an XYLine, which LatLonShape (and XYShape itself up to 8.4.1) rejects with IllegalArgumentException; the accepted query silently returns only indexed points lying on the line and never an indexed line, not even one identical to the query line (the check was lost in LUCENE-9194, 8.5.0)
Area
core / document: XYShape queries (XYShape.newLineQuery and newGeometryQuery, XYShapeQuery, Line2D)
Priority
Low, rank 406: XYShape accepts WITHIN with a line query and silently returns only on-line points, but asking which shapes lie WITHIN a line is unusual.
Impact class
wrong error
Impact note
Applications that build a cartesian shape query with XYShape.newLineQuery or newGeometryQuery, relation WITHIN and an XYLine (alone or inside a geometry array such as [polygon, line]), directly or through a downstream engine that passes the relation and geometry through, get no IllegalArgumentException, unlike LatLonShape and XYShape before 8.5.0, and instead a silently partial answer: indexed points and multi-points lying on the line match, indexed lines never do, not even the identical line; default IndexWriterConfig, codec and searcher, any index size; query-time only, so other queries and the index are unaffected; LatLonShape is not affected; released since 8.5.0.
Summary
You build XYShape.newLineQuery(field, QueryRelation.WITHIN, line) with a valid XYLine and expect the IllegalArgumentException that LatLonShape.newLineQuery throws for the same relation ('does not support WITHIN queries with line geometries'), and that XYShape itself threw up to 8.4.1 ('XYShapeLineQuery does not support WITHIN queries'). Instead the query is accepted, because the XYShapeQuery constructor has validated nothing since LUCENE-9194 (8.5.0) folded the old XY line query into it. The search then returns indexed points that lie on the line but no indexed line, not even one identical to the query line, because Line2D.containsLine and containsTriangle always return false.
Introduced
73dbf6d06108e9f18423521e339230bda37f8524 (master, now main), backported to branch_8x as 5c1f2ca22a756b16f0e35aa5dde221578fe1ce76; both 'LUCENE-9194: Simplify XYShapeXQuery API by adding a new abstract class called XYGeometry' (the commit subject reads 'UCENE-9194') by iverase, PR apache/lucene-solr#1224 (one approval by nknize, no line comments; issue now apache/lucene#10234) [read: git log, blame and git log -G in the full-history clone; the commit deletes XYShapeLineQuery, whose constructor threw 'XYShapeLineQuery does not support WITHIN queries', and routes XYShape.newLineQuery through newGeometryQuery to XYShapeQuery, whose constructor checks neither relation nor geometry; no later commit re-adds a check; the current constructor body dates from d7fd48c9502 (LUCENE-10654, 2022), a refactor that left XY unchanged]. A regression, not born with the feature: XYShapeLineQuery (LUCENE-8632, 0c09481374c, 2019-07-08) documented 'QueryRelation.WITHIN queries are not yet supported' and threw, and one week before LUCENE-9194 the same author carried the identical check into the LatLon twin (LUCENE-9141, a9482911a82, 2020-01-30). The release boundary is executed (8.4.1 rejects, 8.5.0 accepts); no commit-level A/B build was made. LUCENE-9273 (f914e08b364, 2020-04-20, 8.6.0) later made Line2D.containsLine and containsTriangle return false; the observed result is the same before and after it, so it is not the introducing change (2020-02-07 (author and commit date of 73dbf6d0610 and 5c1f2ca22a7; PR #1224 merged the same day))
First affected version
8.5.0 [exec] (8.2.0 and 8.4.1, where XYShape still lived in the sandbox module, throw IllegalArgumentException 'XYShapeLineQuery does not support WITHIN queries' [exec]; the XYShape API did not exist before 8.2.0 [read]; the move to core, LUCENE-8621, also landed in 8.5.0, so XYShape has been affected for its whole time in core)
Affected versions
every release from 8.5.0 to 10.5.2, 52 releases (19 on 8.x: 8.5.0-8.11.4; 21 on 9.x: 9.0.0-9.12.3; 12 on 10.x: 10.0.0-10.5.2), 10.6.0 (by reading: branch_10_6 keeps the same XYShapeQuery constructor) and main ea57360912ed (unreleased 11.0) [exec: a version-neutral JUnit asserting the rejection and the finder's JUnit both fail on 8.5.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea; main also -da), follow-up, 19 runs, each as expected; the independent reproduction's JUnit fails 3 run / 2 failed on main (-ea and -da), 10.5.2 and 9.12.3; the intended-behaviour check re-ran the finder's on main (-ea and -da) and 10.5.2; the other 46 releases [read: a static scan of every cached release jar finds no WITHIN rejection string in any core XYShape* class, positive control: the string is present in the 8.2.0-8.4.1 sandbox jars]]. Not affected: 8.2.0-8.4.1 (sandbox module, rejects) [exec 8.2.0 and 8.4.1; scan 8.3.0-8.4.0]; before 8.2.0 the API is absent [read]. Not fixed upstream: upstream main and branch_10x last changed XYShapeQuery.java on 2022-08-09 (d7fd48c9502), and no open apache/lucene PR touches XYShapeQuery.java, XYShape.java, Line2D.java or LatLonShapeQuery.java [read: GitHub commits API and the file lists of all 410 open PRs, 2026-10-26]. All runs on aarch64 Linux with JDK 25
Status
documented (brief, checks and a per-finding doc exist)
Verification
Confirmed by AI-run checks: an independent repro, a cross-model review that could only read the code (its low-confidence “not real” is procedural), an intended-behaviour check, a prior-report search and a skeptical audit; not yet triaged by a person.
Found by
non-formal: code reading
Upstream and prior reports
none found (2026-10-26, read-only; the prior-report record verdict new): three scripted prior-report searches (58 queries over apache/lucene issues, PRs and commits, downstream repositories, the JIRA archive and the dev@, java-user@, issues@ and commits@ lists; 21, 105 and 58 distinct hits), 10 manual GitHub issue searches (apache/lucene-solr, two downstream engines, the whole of GitHub) and 3 code searches, 5 JIRA text searches, 7 web queries, the file lists of all 410 open apache/lucene PRs, and reads of 6 old lucene-solr PRs and 21 further issues, PRs and JIRA entries; 23 hits classified in the prior-report record, none the same bug; the finder's run (15 queries) and the intended-behaviour check's list run (20 queries) found nothing either. Context, not this bug: elastic/elasticsearch#70648 (closed 2022; a downstream geo_shape user hit the LatLon WITHIN+linestring rejection and a Lucene spatial committer replied that line and WITHIN are not supported by Lucene; geographic path only, XYShape never mentioned; supports the 'missing rejection' framing), apache/lucene#10234 / apache/lucene-solr#1224 (LUCENE-9194, the introduction; nothing on WITHIN), #10181 / lucene-solr#1170 (LUCENE-9141, the LatLon twin keeping the check), #9678 (LUCENE-8632) and #9600 (LUCENE-8554) (origin of the rejection and of the test constant that excludes WITHIN for line queries), #10313 (LUCENE-9273, Line2D.containsLine returning false), lucene-solr#2155 (LUCENE-9641, LatLon kept the rejection, XY did not), open #9782 (LUCENE-8736) and #9680 (LUCENE-8634) (other WITHIN and quantization bugs). Not fixed: upstream main and branch_10x last changed XYShapeQuery.java on 2022-08-09. Gaps: GitHub and list search are keyword-based, and some phrasings ran only once because of rate limiting; private security reports are not visible
Lucene commit tested
main a9779ef3c193 (2026-10-26): this doc's gradle runs in a scratch worktree (stock and with the fix, assertions on and off) and classpath runs; the hunt's runs of the version-neutral rejection test and the finder's test on 8.2.0, 8.4.1, 8.5.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0 and 10.5.2 (Maven Central jars) and on main ea57360912ed, plus a static scan of every other release jar. OpenJDK 25.0.3 on Linux aarch64.

Lucene and upstream sources

Finding record
  • lucene/core/src/java/org/apache/lucene/document/XYShapeQuery.java:37 (at ea57360912ed) (@lucene.internal), :41-44 (constructor: super(field, queryRelation, geometries), no validation), :109-143 (within() leaf predicate: POINT -> component2D.contains(x, y) at :119, LINE -> containsLine at :127, TRIANGLE -> containsTriangle at :137)
  • lucene/core/src/java/org/apache/lucene/document/LatLonShapeQuery.java:43-61 (at ea57360912ed) (validateGeometries: '// TODO: line queries do not support within relations', IllegalArgumentException 'LatLonShapeQuery does not support WITHIN queries with line geometries'); LatLonPointQuery.java:52-63 and LatLonDocValuesQuery.java:63-71 (the same rule)
  • lucene/core/src/java/org/apache/lucene/geo/Line2D.java:85-90 (at ea57360912ed) (contains(x, y): exact point-on-line test), :92-104 (relate never returns CELL_INSIDE_QUERY), :142-170 (containsLine '// can be improved?' and containsTriangle return false); lucene/core/src/java/org/apache/lucene/geo/Component2D.java:73 ('return true if this component2D contains the provided line')
  • lucene/core/src/java/org/apache/lucene/document/XYShape.java:62-63 (at ea57360912ed) (class javadoc: newLineQuery matches shapes 'that have some QueryRelation with a linestring'), :219-225 (newLineQuery: 'find all cartesian shapes that intersect a provided linestring', delegates to newGeometryQuery), :261-272 (newGeometryQuery: builds new XYShapeQuery with any relation)
  • lucene/core/src/test/org/apache/lucene/document/BaseSpatialTestCase.java:62-64 (at ea57360912ed) and :415 (line queries draw only from POINT_LINE_RELATIONS = {INTERSECTS, DISJOINT, CONTAINS}, so XY WITHIN with a line is never tested)
The finding in 30 seconds
  • lucene/core/src/java/org/apache/lucene/document/XYShape.java:219-225, 261-272
  • lucene/core/src/java/org/apache/lucene/document/XYShapeQuery.java:41-44, 108-144
  • lucene/core/src/java/org/apache/lucene/document/LatLonShapeQuery.java:43-61; LatLonPointQuery.java:52-63; LatLonDocValuesQuery.java:63-73; LatLonPoint.java:314-316
  • lucene/core/src/java/org/apache/lucene/geo/Line2D.java:84-90, 92-104, 142-154, 156-169
  • lucene/core/src/java/org/apache/lucene/document/SpatialQuery.java:74-85; geo/XYGeometry.java:24-44; geo/EdgeTree.java:146-168; geo/GeoUtils.java:196-204; geo/ComponentTree.java:88-108, 333-356; document/ShapeField.java:374-377
Why it looks unintended
  • lucene/core/src/java/org/apache/lucene/document/LatLonShapeQuery.java:43-61; LatLonPointQuery.java:52-63; LatLonDocValuesQuery.java:63-73; LatLonPoint.java:314-316
  • lucene/core/src/java/org/apache/lucene/document/XYShape.java:62-63, 219-222, 227-230; XYShapeQuery.java:37; LatLonShape.java:286-289
  • lucene/CHANGES.txt:6023-6027 (LUCENE-9141, LUCENE-9194)
  • lucene/core/src/test/org/apache/lucene/document/BaseSpatialTestCase.java:62-64, 415
  • grep of lucene/*/src/test and lucene/test-framework/src at a9779ef3c193: no test asserts a WITHIN + line rejection or result
Suggested fix
  • lucene/core/src/java/org/apache/lucene/document/LatLonShapeQuery.java:43-61; LatLonPoint.java:314-316; geo/Line2D.java:142-169
  • lucene/core/src/java/org/apache/lucene/document/XYShapeDocValuesQuery.java:29-33; XYShape.java:214-217; ShapeDocValuesField.java:89-95
History
  • a Lucene clone: git show 20ced71c1e6, 1309534296e and 2763db11b0a of XYShapeQuery.java; git diff --stat a9779ef3c193 20ced71c1e6 for XYShapeQuery.java, XYShape.java, Line2D.java, LatLonShapeQuery.java (no change)

Other statements trace to the hunt's working files (models, logs, reviews and briefs), which are not published.

Repro files

About the diagrams

Built 2026-11-03 from the hunt's record of this finding and its doc file. Lucene main under test in this hunt: ea57360912ed. Every listed finding was re-run on Lucene main e1faeba08bde on 2026-11-02.