Skip to content

Address API Failure Handling Issues #29

Description

@mwaddell

API Failure-Handling Issues

This document records findings from a review of API failure handling across the
CLI, shared provider logic, Census, Google, and Geocodio integrations.

High Priority

Geocodio Error Entries Can Be Cached As No-Matches

Relevant code: src/geocodio.py:87-99, src/geocodio.py:118-120.

Geocodio responses with a successful HTTP status and a correctly sized results
array are cached before each entry is parsed. If an entry contains an embedded
provider error instead of normal candidates, parse() treats it as a no-match
and the error payload becomes a persistent cached response.

Impact:

  • Transient quota, validation, or provider-side errors can be reported as valid
    no-matches.
  • Re-running the same query returns the cached no-match until the cache is
    deleted.

Recommended remediation:

  • Validate each entry for documented error fields before yielding it for caching.
  • Raise a provider-specific error for authentication, quota, request, malformed
    response, and service failures.
  • Add a test showing embedded error entries are not cached.

Google Malformed OK Payloads Raise Low-Context Exceptions

Relevant code: src/google.py:120-124, src/google.py:149-175.

After accepting status == "OK", Google parsing unconditionally accesses
raw["results"][0]. Missing, empty, or incorrectly typed results cause a
KeyError, IndexError, or TypeError. Malformed nested geometry or address
components can fail similarly.

Impact:

  • Users receive implementation exceptions rather than a useful provider error.
  • A provider schema change is difficult to diagnose.

Recommended remediation:

  • Validate that results is a non-empty list containing a mapping before it is
    cached or parsed.
  • Raise a descriptive provider-specific error containing the response status and
    a sanitized payload summary.
  • Add tests for missing, empty, and malformed results and nested fields.

Census Response IDs Are Not Validated One-To-One

Relevant code: src/census.py:103-110, src/api.py:284-292.

Census validates response row count but does not verify that returned record IDs
are numeric, unique, and exactly match submitted IDs. An unknown ID is silently
ignored. A submitted record missing from the yielded responses becomes a
no-match in the shared provider code.

Impact:

  • A malformed or misaligned Census batch response can be silently reported as a
    legitimate no-match.
  • Partial batch results can be cached before the mismatch is detected.

Recommended remediation:

  • Validate that each response ID is numeric, belongs to the submitted batch,
    appears exactly once, and collectively covers the batch.
  • Raise a descriptive error on any protocol mismatch.
  • Add tests for unknown, duplicate, missing, blank, and non-numeric IDs.

Medium Priority

Retry Policy Retries Permanent HTTP Failures

Relevant code: src/api.py:294-329.

The retry helper retries every requests.RequestException, including HTTP 4xx
responses that are normally permanent, such as rejected credentials and invalid
requests. It does not honor Retry-After on rate limits and uses fixed linear
backoff without jitter.

Impact:

  • Users wait unnecessarily before receiving permanent failure messages.
  • Rate-limited requests may retry too aggressively or too slowly.

Recommended remediation:

  • Retry connection/time-out errors, HTTP 429, and selected HTTP 5xx responses.
  • Fail immediately for other 4xx responses.
  • Honor Retry-After when supplied and use bounded exponential backoff with
    jitter.
  • Add tests for 401, 403, 404, 429, 5xx, timeouts, and Retry-After behavior.

Invalid JSON Is Not Reported With Provider Context

Relevant code: src/google.py:91-100, src/geocodio.py:87-98.

Google and Geocodio call response.json() without translating JSON decoding
errors. A proxy page, malformed body, or non-JSON provider response leaks a raw
decoder exception without provider name, HTTP status, or response context.

Impact:

  • Diagnosis of upstream service or network-proxy failures is difficult.

Recommended remediation:

  • Catch response JSON decode errors.
  • Raise a provider-specific error containing provider name, HTTP status, and a
    bounded, sanitized response excerpt.
  • Confirm invalid JSON responses are never cached.

Provider Failure Semantics Are Inconsistent

Relevant code: src/census.py:148-154, src/google.py:84-89,
src/geocodio.py:118-125.

Census treats unrecognized statuses as no-match, Google raises for all statuses
other than OK and ZERO_RESULTS, and Geocodio treats missing candidates as a
no-match. The distinction between an actual no-match and a provider failure is
not consistently schema-validated.

Impact:

  • Equivalent provider failures may be handled differently.
  • Some invalid responses can be cached as no-matches.

Recommended remediation:

  • Define a shared provider contract.
  • Normalize only documented no-match responses and allow them to be cached.
  • Raise and avoid caching authentication, quota, validation, service, and
    malformed-schema failures.

Low Priority

CLI Presentation Is Inconsistent For Provider Failures

Relevant code: src/geocoder.py:397-407, src/api.py:324-329.

The CLI converts missing API keys and cache setup failures into readable
SystemExit messages, but transport failures and provider ValueErrors escape
as tracebacks.

Impact:

  • Routine operational API failures are less clear for command-line users.

Recommended remediation:

  • Catch expected transport and provider exceptions at the CLI boundary.
  • Print concise error: messages.
  • Preserve tracebacks behind an explicit debug or verbose mode rather than
    broadly suppressing programmer errors.

Existing Strengths

  • Every provider request uses a finite timeout.
  • Shared retry logic handles request exceptions and re-raises the final failure.
  • Google raises non-success application statuses before caching.
  • Census validates matched-row layout, numeric coordinates, and batch row count.
  • Geocodio validates batch entry count.
  • Cache creation and read-only cache validation fail early with clear messages.
  • Tests verify Google application errors are not cached.

Missing Failure Tests

  • Google: malformed OK payloads, including missing or empty results.
  • Google: malformed result, geometry, location, and address-components
    values.
  • Google: invalid JSON response is contextualized and never cached.
  • Geocodio: HTTP-success error envelope without results.
  • Geocodio: per-entry error payload is rejected and never cached.
  • Geocodio: malformed JSON and incorrectly typed results values.
  • Census: unknown, duplicate, missing, blank, and non-numeric response IDs.
  • Census: malformed non-match and tie rows.
  • Shared retry policy: 401, 403, 404, 429, 5xx, timeouts, and Retry-After.
  • CLI: provider transport and schema failures produce expected user-facing
    messages.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

apiThis task modifies existing API support or adds support for a new Geocoding API

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions