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.
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.- 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). - You ask which shapes lie WITHIN that line:
XYShape.newLineQuery("shape", QueryRelation.WITHIN, line (0,0)-(10,0)). - You expect an
IllegalArgumentException:LatLonShaperejects the same query ("does not support WITHIN queries with line geometries"), andXYShapeitself did up to 8.4.1. - 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.
- Why: the
XYShapeQueryconstructor 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 withLine2D.containsLine, which always returns false.
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.
- XYShape: Lucene's field for cartesian (unitless x, y) shapes.
XYShape.createIndexableFieldsindexes a polygon as triangles, a line as one segment per pair of consecutive vertices, and a point as a point. Its twinLatLonShapedoes 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.
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).
The WITHIN leaf test (XYShapeQuery.java:108-144) checks each indexed piece against Line2D:
| indexed piece | test | result 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 line | containsLine (:127) -> Line2D.java:142-154: // can be improved? return false; | false: never matches |
| segment (2,0)-(4,0) | the same containsLine | false: never matches |
| triangle of a polygon | containsTriangle (: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.
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 anXYLine, alone or inside a geometry array such as[polygon, line], directly or through a downstream query layer. Two downstream engines' cartesian shape queries callXYShape.newGeometryQuerywith 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,LatLonPointandLatLonDocValuesField(they reject), andXYShapeWITHIN queries whose geometries contain noXYLine(they never meetLine2D). - 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.
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).
/*
* 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));
}
}
# 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, asLatLonShape.newLineQuerythrows and XYShape threw up to 8.4.1; actual: no exception (-ea and -da).
More files, environment, full output37 words
| lucene | Lucene main e1faeba08bde (2026-11-02) |
|---|---|
| jdk | 25.0.3+9-LTS |
# 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)LatLonShape,LatLonPointandLatLonDocValuesFieldreject WITHIN with a line ("TODO: line queries do not support within relations").XYShaperejected 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,LatLonPointQueryandLatLonDocValuesQueryall throw for WITHIN with a line, each with// TODO: line queries do not support within relations;LatLonPoint.newGeometryQuerydocuments "Line geometries are not supported for WITHIN relationship". - XY itself rejected it until 8.5.0.
XYShapeLineQuery(LUCENE-8632, 2019) documented "QueryRelation.WITHINqueries 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
LatLonShapeQueryand kept the check; LUCENE-9641 (2021, the same author) added the rejection to the newLatLonPointQueryandLatLonDocValuesQueryand rewroteXYShapeQueryin 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.
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, ...)andnewGeometryQuery(f, WITHIN, ...)with anyXYLinein 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 anIllegalArgumentExceptionfor 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
XYShapeQueryonly.XYShapeDocValuesQueryextendsBaseShapeDocValuesQuerydirectly and would not get it, but no public API builds it with a line today:XYShape.newSlowDocValuesBoxQuerypasses only anXYRectangle(XYShape.java:214-217) andShapeDocValuesField.newGeometryQueryalways 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 oflucene/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(thegeopackage,document*Shape*,TestXY*andTestLatLon*,searchTestXY*andTestLatLon*; 54 classes with the repro) passes: 587 tests, 40 skipped, 0 failures. - Lint and format:
ecjLintMainpasses 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 testecjLintTestandcheckGoogleJavaFormatpass, 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.diffandfix-with-test.diff(the fix plus the test as a new file) passgit apply --checkona9779ef3c193(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).
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.
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 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.
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.validateGeometriesexists only on the LatLon side; a class-file scan for the same idiom agreed (present inLatLonShapeQuery, absent inXYShapeQuery). - The git history showed that
XYShapeLineQueryrejected 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.
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.
| Where | When | How | Found |
|---|---|---|---|
| apache/lucene issues, PRs and commits; downstream repositories; the JIRA archive; dev@, java-user@, issues@, commits@ | 2026-10-26 | the 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 runs | no 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 web | 2026-10-26 | 10 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_10x | 2026-10-26 | changed-file lists; commit history of the files | no open PR touches XYShapeQuery.java, XYShape.java, Line2D.java or LatLonShapeQuery.java; XYShapeQuery.java last changed 2022-08-09 |
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.
| Version or commit | Verdict | Result |
|---|---|---|
main a9779ef3c193 | affected | accepted: 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) | affected | 10.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) | affected | 9.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.0 | 8.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 query | 8.2.0 and 8.4.1 executed: IllegalArgumentException "XYShapeLineQuery does not support WITHIN queries"; before 8.2.0 there is no XYShape |
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.
| Check | Verdict | What it found |
|---|---|---|
| finder | candidate | Twin 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 | real | Own 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, medium | The strongest "works as designed" case, rated moderate, justifies a rejection, not silent partial matching. |
| intended-behaviour devil's advocate | real, framed as the missing rejection | Executed 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, high | Re-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 | keep | Re-ran both repros on main ea57360912ed; the re-verification on a9779ef3c193 still reproduces both. |
| this doc | reproduced; fix validated | Gradle 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. |
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.
- PNG 576 KB
Finding record, Lucene and upstream sources, repro files and diagram notes1,444 words
- 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 mainea57360912ed, plus a static scan of every other release jar. OpenJDK 25.0.3 on Linux aarch64.
- 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-272lucene/core/src/java/org/apache/lucene/document/XYShapeQuery.java:41-44, 108-144lucene/core/src/java/org/apache/lucene/document/LatLonShapeQuery.java:43-61; LatLonPointQuery.java:52-63; LatLonDocValuesQuery.java:63-73; LatLonPoint.java:314-316lucene/core/src/java/org/apache/lucene/geo/Line2D.java:84-90, 92-104, 142-154, 156-169lucene/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-316lucene/core/src/java/org/apache/lucene/document/XYShape.java:62-63, 219-222, 227-230; XYShapeQuery.java:37; LatLonShape.java:286-289lucene/CHANGES.txt:6023-6027 (LUCENE-9141, LUCENE-9194)lucene/core/src/test/org/apache/lucene/document/BaseSpatialTestCase.java:62-64, 415grep 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-169lucene/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)
- TestXYShapeWithinLineRejected.java (JUnit test):
repro/LFV-434/src/org/apache/lucene/document/TestXYShapeWithinLineRejected.java(32 lines)
assets/LFV-434/bug.png(576 KB)
