Summary

  • PeeringDB’s 21 October 2.84.0 release lists a fix for RIR-driven network and exchange-connection deletions that its ?since= incremental API had failed to report. The original issue describes hard-deleted netixlan rows and some network rows whose updated timestamp did not move.
  • The fix changes the future deletion path and adds a regression test for visible tombstones. It does not retroactively update copies that already kept deleted records. The issue’s reporter says a full resync is needed for that older drift; no public count of affected clients or completed resyncs is available.

The cable that stayed in the copy

Picture an interconnection planner checking a network’s presence at an exchange. The public PeeringDB record is gone. A local mirror still offers the connection as a current row. The directory describes an exchange presence. A BGP session ledger would answer whether traffic flowed. Here, the source and its working copy give two answers to the same directory question because removal never reached the copy.

PeeringDB encourages local use. Its API specifications describe ?since= as a way to request objects changed since a Unix timestamp and say deleted objects can be retrieved by filtering for status=deleted with a positive since value. Its public FAQ says a peeringdb-py cache begins with a full copy and then takes incremental updates. The bargain is simple: clients spare the source repeated full reads, and the source sends each meaningful change. A deletion is as meaningful as an addition. A mirror that receives additions but silently misses removals becomes a scrapbook of old possibilities.

PeeringDB issue #2057, opened on 7 October by Remco van Mook after comparing a ?since=-synchronized copy with full API listings, identifies the broken handoff. The scheduled RIR-status cleanup could bulk-delete a network’s netixlan entries, the records joining a network to an exchange LAN. That bulk operation bypassed the model’s soft-delete method, which would have changed each row to deleted and advanced its updated timestamp. The row disappeared from the source table without leaving a reportable tombstone. A client polling “what changed since my last visit?” got no answer for that removal.

The issue records a second form of silence: some network rows became deleted while their updated time remained at its older value. The API’s clock filtered them out even though their status had changed. The reporter supplied concrete IDs and timestamps, including examples whose deletion appeared in 2026 while their updated field still showed 2022. The clock was not merely late. For those rows it was pointing at a previous state.

A small code path, a large authority gap

The reporter found 286 hard-deleted netixlan rows associated with 125 networks in roughly six months of comparison, and 46 network deletions without an updated-time bump. Those counts describe the reporter’s comparison; PeeringDB has published no total of affected clients. They establish that the failure was repeatable and had accumulated. The issue also describes records missing in the other direction, including a later comparison of 569 active netixlan rows absent from the synchronized copy. Their exact path was still unresolved in that comment: a long transaction could have made rows visible after the timestamp used by a client, or restoration might have failed to advance it. The separate cause still needs a traced timestamp and commit sequence.

The defect matters because PeeringDB’s record sits upstream of many independent decisions. A network may use a local cache for planning, monitoring or automation. An exchange may publish its members, and a prospective peer may decide whom to contact. A stale row could waste a request or confuse a comparison between a directory listing and an operator’s own records. The reported failure is in data consistency. It offers a straightforward route to false confidence: a local client can be perfectly synchronized according to its cursor while wrong about whether a row exists.

PeeringDB merged commit 81ac767 on 20 October. The change removes the explicit bulk delete of active exchange-connection rows and lets the network’s own deletion path handle them. The added test creates a network, exchange connections and a technical contact; runs the RIR-status deletion; then checks that the network and its connections have deleted status, newer timestamps and deleted connection rows in a ?since= API response. That is the right kind of test: it checks the external evidence a client can consume, not merely that an internal deletion function returned.

PeeringDB’s release notes date 2.84.0 to 21 October and list issue #2057 as fixing deletions for synchronizing users. The schedule table had named 20 October as the production target. The merge, target and release-note date are separate records; the completed release note is the evidence for the published fix. Its wording does not claim that old client databases were repaired remotely.

The repair ends at the source boundary

A future deletion can now announce itself to a polling client in the tested RIR-status path. That repairs the contract going forward. An already hard-deleted row has no source row left from which to issue a delayed tombstone. A network that changed status while retaining a 2022 updated timestamp will remain invisible to a cursor that begins in 2026. The issue says the client-side remedy for existing divergence is a full resync. There is no public receipt that all mirrors, peeringdb-py installations or consuming tools have done one.

A full resync has a cost: fetching and rebuilding more state than a small delta. That cost is exactly why incremental synchronization exists. Asking every downstream operator to pay it after an upstream deletion fault is a governance choice embedded in an implementation detail. PeeringDB owns the source deletion path and its API contract. Each mirror owner controls the cadence and recovery of its own copy. Neither can truthfully describe a stale local row as current just because the polling job finished without error.

PeeringDB’s separate API v3 draft says delta sync must make deletions and withdrawals visible and daily snapshots should provide bootstrap and fallback. The draft is not a deployed cure for the v2 issue. It is an unusually clean test for the next design: does a deletion have a versioned, consumable identity, and can a client prove that its public projection caught up? The answer cannot come from an uptime percentage alone. A service can answer every request and still omit the one update that matters.

The line that failed was short. A bulk delete removed the port record; the synchronization stream had nothing to say about it. The line that matters is longer: after the fix, the source must publish removal, the client must consume it, and old copies must be reconciled. PeeringDB repaired the first handoff in 2.84.0. The rest of the ghosts live downstream.