Skip to content

[Detail Bug] ETA requests accept invalid RouteLocation coordinates, producing malformed query strings #79

@detail-app

Description

@detail-app

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions