Detail Bug Report
https://app.detail.dev/org_befd6425-a158-4e24-9d4d-1e5c08769515/bugs/bug_1502c764-7bd0-4bef-bdfe-a529a4fc77d6
Introduced in #34 by @WilliamAGH on Jan 23, 2026
Summary
- Context: The author added coordinate validation to
Location and DirectionsEndpoint.fromLatitudeLongitude() but forgot RouteLocation.fromLatitudeLongitude() which has an identical factory method pattern.
- Bug:
RouteLocation.fromLatitudeLongitude() accepts invalid coordinates (NaN, Infinity, out-of-range) without validation, while DirectionsEndpoint.fromLatitudeLongitude() validates the same inputs.
- Actual vs. expected: Actual:
RouteLocation.fromLatitudeLongitude() allows invalid doubles and formats them into query strings (e.g., "NaN,-122.4"). Expected: it should reject invalid/out-of-range coordinates the same way DirectionsEndpoint.fromLatitudeLongitude() does (fail fast with IllegalArgumentException).
- Impact:
RouteLocation is a REQUIRED input in EtaInput. Invalid coordinates can flow into EtaInput.toQueryString() and be sent to the Apple Maps API as malformed query parameters, wasting API calls.
Code with Bug
public static RouteLocation fromLatitudeLongitude(double latitude, double longitude) {
return new RouteLocation(formatCoordinatePair(latitude, longitude));
// <-- BUG 🔴 missing Location.validateLatitudeLongitude; allows NaN/Infinity/out-of-range coords
}
Explanation
Location.validateLatitudeLongitude(latitude, longitude) exists (package-private) and is already used by DirectionsEndpoint.fromLatitudeLongitude(). RouteLocation.fromLatitudeLongitude() uses the same construction pattern but does not call validation, so invalid doubles get formatted into strings and propagated into ETA requests.
Codebase Inconsistency
DirectionsEndpoint.fromLatitudeLongitude() validates before formatting:
public static DirectionsEndpoint fromLatitudeLongitude(double latitude, double longitude) {
Location.validateLatitudeLongitude(latitude, longitude);
return new DirectionsEndpoint(formatCoordinatePair(latitude, longitude));
}
This establishes the intended fail-fast behavior for coordinate-based factory methods in this package.
Failing Test
src/test/java/com/williamcallahan/applemaps/domain/model/RouteLocationValidationTest.java
package com.williamcallahan.applemaps.domain.model;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class RouteLocationValidationTest {
private static final double VALID_LATITUDE = 37.7;
private static final double VALID_LONGITUDE = -122.4;
@Test
void directionsEndpointRejectsNanLatitude() {
assertThrows(
IllegalArgumentException.class,
() -> DirectionsEndpoint.fromLatitudeLongitude(Double.NaN, VALID_LONGITUDE)
);
}
@Test
void routeLocationAcceptsNanLatitude() {
RouteLocation loc = RouteLocation.fromLatitudeLongitude(Double.NaN, VALID_LONGITUDE);
assertEquals("NaN,-122.4", loc.toQueryString());
}
@Test
void routeLocationAcceptsInfiniteLongitude() {
RouteLocation loc = RouteLocation.fromLatitudeLongitude(VALID_LATITUDE, Double.POSITIVE_INFINITY);
assertEquals("37.7,Infinity", loc.toQueryString());
}
@Test
void routeLocationAcceptsOutOfRangeLatitude() {
RouteLocation loc = RouteLocation.fromLatitudeLongitude(999.0, VALID_LONGITUDE);
assertEquals("999.0,-122.4", loc.toQueryString());
}
}
Recommended Fix
Add validation to RouteLocation.fromLatitudeLongitude():
public static RouteLocation fromLatitudeLongitude(double latitude, double longitude) {
Location.validateLatitudeLongitude(latitude, longitude);
return new RouteLocation(formatCoordinatePair(latitude, longitude));
}
History
This bug was introduced in commit f83c5e2. The commit added coordinate validation to Location.validateLatitudeLongitude() and correctly called it from DirectionsEndpoint.fromLatitudeLongitude(), but failed to add the same validation call to RouteLocation.fromLatitudeLongitude(). Both classes were created together in commit 33eca2a with identical factory methods; the inconsistency arose when the validation pattern was introduced and only one of the two was updated.
Detail Bug Report
https://app.detail.dev/org_befd6425-a158-4e24-9d4d-1e5c08769515/bugs/bug_1502c764-7bd0-4bef-bdfe-a529a4fc77d6
Introduced in #34 by @WilliamAGH on Jan 23, 2026
Summary
LocationandDirectionsEndpoint.fromLatitudeLongitude()but forgotRouteLocation.fromLatitudeLongitude()which has an identical factory method pattern.RouteLocation.fromLatitudeLongitude()accepts invalid coordinates (NaN, Infinity, out-of-range) without validation, whileDirectionsEndpoint.fromLatitudeLongitude()validates the same inputs.RouteLocation.fromLatitudeLongitude()allows invalid doubles and formats them into query strings (e.g.,"NaN,-122.4"). Expected: it should reject invalid/out-of-range coordinates the same wayDirectionsEndpoint.fromLatitudeLongitude()does (fail fast withIllegalArgumentException).RouteLocationis a REQUIRED input inEtaInput. Invalid coordinates can flow intoEtaInput.toQueryString()and be sent to the Apple Maps API as malformed query parameters, wasting API calls.Code with Bug
Explanation
Location.validateLatitudeLongitude(latitude, longitude)exists (package-private) and is already used byDirectionsEndpoint.fromLatitudeLongitude().RouteLocation.fromLatitudeLongitude()uses the same construction pattern but does not call validation, so invalid doubles get formatted into strings and propagated into ETA requests.Codebase Inconsistency
DirectionsEndpoint.fromLatitudeLongitude()validates before formatting:This establishes the intended fail-fast behavior for coordinate-based factory methods in this package.
Failing Test
src/test/java/com/williamcallahan/applemaps/domain/model/RouteLocationValidationTest.javaRecommended Fix
Add validation to
RouteLocation.fromLatitudeLongitude():History
This bug was introduced in commit f83c5e2. The commit added coordinate validation to
Location.validateLatitudeLongitude()and correctly called it fromDirectionsEndpoint.fromLatitudeLongitude(), but failed to add the same validation call toRouteLocation.fromLatitudeLongitude(). Both classes were created together in commit 33eca2a with identical factory methods; the inconsistency arose when the validation pattern was introduced and only one of the two was updated.