You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[BUG] A failed Geo database refresh deletes the last known good copy, so country blocking fails open until restart #78
The download that failed is a refresh — the file on disk was working a
moment ago. Deleting it and clearing the reader means every subsequent get_country() returns nothing, so blocked_countries and whitelist_countries
both stop matching. Country blocking is off until a later refresh succeeds, and
nothing retries within the process.
An outage at ipinfo.io, a token that expired, or a proxy that briefly refuses
egress all take a working geo policy off. That is the wrong direction for a
transient failure: a stale MMDB is a far better answer than no MMDB.
Fix: keep the existing file and the existing reader on download failure. Delete
only when the file is genuinely unusable — maxminddb.open_database raising is
the signal — and log the staleness so last_refreshed in the status route
reflects it.
Found while re-checking a private audit against the current release. Verified on guard-core 3.13.0, CPython 3.14.
Reproduced. It is two defects, not one. initialize() unlinks the good file on any download exception, and since the download reads the whole body before it opens db_path, the file is provably untouched when the common failures (HTTP error, timeout, expired token) fire. Separately, refresh() sets reader = None before it even attempts the download and never reopens the existing file when the download fails, so a failed refresh loses the reader regardless of what happens to the file. Both since the first commit.
Fix in 3.14.0: keep the last-known-good file and reader on download failure; delete only when maxminddb.open_database raises (currently unguarded, and the actual corruption signal); last_refreshed stops advancing on failure so the status route shows staleness.
A failed GeoIP refresh or download keeps the last known good database and reader; downloads go to a temporary file that is swapped in atomically, and only a database that fails to open is discarded.
Activity
rennf93 commentedon Aug 25, 2026
Thanks @RomanPszonka for opening the issue! By @rennf93's directive:
Reproduced. It is two defects, not one.
initialize()unlinks the good file on any download exception, and since the download reads the whole body before it opensdb_path, the file is provably untouched when the common failures (HTTP error, timeout, expired token) fire. Separately,refresh()setsreader = Nonebefore it even attempts the download and never reopens the existing file when the download fails, so a failed refresh loses the reader regardless of what happens to the file. Both since the first commit.Fix in 3.14.0: keep the last-known-good file and reader on download failure; delete only when
maxminddb.open_databaseraises (currently unguarded, and the actual corruption signal);last_refreshedstops advancing on failure so the status route shows staleness.rennf93 commentedon Aug 26, 2026
Shipped in guard-core 3.14.0 (PyPI), merged in #82 (500d4ef).
A failed GeoIP refresh or download keeps the last known good database and reader; downloads go to a temporary file that is swapped in atomically, and only a database that fails to open is discarded.