Detail Bug Report
https://app.detail.dev/org_befd6425-a158-4e24-9d4d-1e5c08769515/bugs/bug_f521d3bd-7947-463d-a905-bc531c98cc91
Introduced in 33eca2a by @WilliamAGH on Jan 15, 2026
Summary
- Context:
PlaceLookupErrorCode is an enum defining error codes for Apple Maps place lookup API responses, used by the PlaceLookupError record.
- Bug: Unknown error codes cause the entire response deserialization to fail, losing all valid data in the response.
- Actual vs. expected: When Apple returns an unknown error code in ANY error object, deserialization throws
ValueInstantiationException with cause NullPointerException, and the entire PlacesResponse or AlternateIdsResponse fails to parse. The codebase pattern for other enums is to degrade gracefully via Optional<T>.
- Impact: A single unknown error code in a batch response causes loss of ALL valid results and errors.
Code with Bug
// PlaceLookupError.java:11-23
public record PlaceLookupError(
PlaceLookupErrorCode errorCode, // <-- BUG 🔴 not forward-compatible; unknown enums become null
@JsonProperty("id") String rawId
) {
public PlaceLookupError {
Objects.requireNonNull(errorCode, "errorCode"); // <-- BUG 🔴 throws when ObjectMapper maps unknown enum to null
}
}
// AppleMapsObjectMapperFactory.java:31
.enable(EnumFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL) // Unknown enums become null
Explanation
The ObjectMapper is configured with READ_UNKNOWN_ENUM_VALUES_AS_NULL, so when Apple introduces a new error code string, Jackson maps it to null for PlaceLookupErrorCode. PlaceLookupError’s compact constructor requires errorCode non-null, throwing NullPointerException, which Jackson wraps as ValueInstantiationException. Because this occurs while deserializing the errors array, the entire parent response (PlacesResponse / AlternateIdsResponse) fails to parse, and valid results in the same payload are lost.
Codebase Inconsistency
Other external-API enums in the codebase are treated as forward-compatible by wrapping them in Optional<T> and normalizing nulls to Optional.empty() (e.g., POI categories), and there is explicit test coverage ensuring unknown values are ignored:
// AppleMapsObjectMapperFactoryTest.java:13-48
@Test
void unknownPoiCategoryIsIgnored() throws Exception {
// JSON with "poiCategory": "NewCategoryAppleAdded"
SearchResponse response = objectMapper.readValue(json, SearchResponse.class);
assertEquals(Optional.empty(), response.results().get(0).poiCategory());
}
PlaceLookupErrorCode handling violates this established pattern.
Failing Test
src/test/java/com/williamcallahan/applemaps/domain/model/PlaceLookupErrorUnknownCodeTest.java
@Test
void demonstratesBug_UnknownErrorCodeCausesValueInstantiationException() {
ValueInstantiationException ex = assertThrows(
ValueInstantiationException.class,
() -> OBJECT_MAPPER.readValue(JSON_WITH_UNKNOWN_ERROR_CODE, PlaceLookupError.class)
);
assertTrue(ex.getCause() instanceof NullPointerException,
"Expected NPE as root cause, got: " + ex.getCause());
assertTrue(ex.getMessage().contains("errorCode"),
"Expected error message to mention 'errorCode'");
}
@Test
void demonstratesBug_BatchWithUnknownErrorCodeFailsEntireResponse() {
// ... asserts same failure for PlacesResponse with valid results
}
Test output excerpt:
tools.jackson.databind.exc.ValueInstantiationException: Cannot construct instance of
`com.williamcallahan.applemaps.domain.model.PlaceLookupError`, problem: errorCode
...
Caused by: java.lang.NullPointerException: errorCode
at java.base/java.util.Objects.requireNonNull(Objects.java:235)
at com.williamcallahan.applemaps.domain.model.PlaceLookupError.<init>(PlaceLookupError.java:22)
Recommended Fix
Match the existing forward-compatibility pattern by making the enum optional and normalizing nulls:
public record PlaceLookupError(
Optional<PlaceLookupErrorCode> errorCode,
@JsonProperty("id") String rawId
) {
public PlaceLookupError {
errorCode = normalizeOptional(errorCode);
}
private static <T> Optional<T> normalizeOptional(Optional<T> optionalInput) {
return Objects.requireNonNullElse(optionalInput, Optional.empty());
}
}
History
This bug was introduced in commit 33eca2a. The initial domain models commit established the pattern of wrapping forward-compatible enums in Optional<T> (e.g., TransportType, PoiCategory) with null-safe normalization, but PlaceLookupErrorCode was added as a bare enum type with Objects.requireNonNull(errorCode), creating an inconsistency from the start. The ObjectMapper configuration added 25 seconds later in 3480a9e enabled READ_UNKNOWN_ENUM_VALUES_AS_NULL, which made the bug triggerable via the specific NPE failure path.
Detail Bug Report
https://app.detail.dev/org_befd6425-a158-4e24-9d4d-1e5c08769515/bugs/bug_f521d3bd-7947-463d-a905-bc531c98cc91
Introduced in 33eca2a by @WilliamAGH on Jan 15, 2026
Summary
PlaceLookupErrorCodeis an enum defining error codes for Apple Maps place lookup API responses, used by thePlaceLookupErrorrecord.ValueInstantiationExceptionwith causeNullPointerException, and the entirePlacesResponseorAlternateIdsResponsefails to parse. The codebase pattern for other enums is to degrade gracefully viaOptional<T>.Code with Bug
Explanation
The ObjectMapper is configured with
READ_UNKNOWN_ENUM_VALUES_AS_NULL, so when Apple introduces a new error code string, Jackson maps it tonullforPlaceLookupErrorCode.PlaceLookupError’s compact constructor requireserrorCodenon-null, throwingNullPointerException, which Jackson wraps asValueInstantiationException. Because this occurs while deserializing theerrorsarray, the entire parent response (PlacesResponse/AlternateIdsResponse) fails to parse, and valid results in the same payload are lost.Codebase Inconsistency
Other external-API enums in the codebase are treated as forward-compatible by wrapping them in
Optional<T>and normalizing nulls toOptional.empty()(e.g., POI categories), and there is explicit test coverage ensuring unknown values are ignored:PlaceLookupErrorCodehandling violates this established pattern.Failing Test
src/test/java/com/williamcallahan/applemaps/domain/model/PlaceLookupErrorUnknownCodeTest.javaTest output excerpt:
Recommended Fix
Match the existing forward-compatibility pattern by making the enum optional and normalizing nulls:
History
This bug was introduced in commit 33eca2a. The initial domain models commit established the pattern of wrapping forward-compatible enums in
Optional<T>(e.g.,TransportType,PoiCategory) with null-safe normalization, butPlaceLookupErrorCodewas added as a bare enum type withObjects.requireNonNull(errorCode), creating an inconsistency from the start. The ObjectMapper configuration added 25 seconds later in 3480a9e enabledREAD_UNKNOWN_ENUM_VALUES_AS_NULL, which made the bug triggerable via the specific NPE failure path.