NIP-IA: failed kind:13535 snapshot publish is unrepairable — changed=false early return skips publish_nipia_archival_list on every retry
- Dominant language
- Rust
- Stars
- 32.7k
- Forks
- 4.3k
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 253
Description
**Describe the bug**
If the relay-signed `kind:13535` archived-identities snapshot fails to publish during a NIP-IA archive request, that snapshot is permanently stale for the affected identity — and no number of retries by the client can repair it.
The failure chain:
1. `handle_identity_archive_event` calls `db.archive(...)`, which inserts with `ON CONFLICT (community_id, pubkey) DO NOTHING` and returns `changed = rows_affected > 0` (https://github.com/block/buzz/blob/ac4fa13b8e4d947071d57deb6918dcf12bf74961/crates/buzz-db/src/archived_identities.rs#L60-L77).
2. On the first (successful) archive, the `kind:8002` delta and `kind:13535` snapshot publishes are attempted, but their errors are only `warn!`-logged (https://github.com/block/buzz/blob/ac4fa13b8e4d947071d57deb6918dcf12bf74961/crates/buzz-relay/src/handlers/identity_archive.rs#L131-L136). The handler still returns `Ok(())`.
3. Any subsequent archive request for the same identity hits `changed == false` and returns early — before `publish_nipia_archival_list` is ever reached (https://github.com/block/buzz/blob/ac4fa13b8e4d947071d57deb6918dcf12bf74961/crates/buzz-relay/src/handlers/identity_archive.rs#L100-L102).
So the one code path that could republish the snapshot is gated behind a DB state transition that, by design, can only happen once. Retrying the archive request is an idempotent no-op: the DB row exists, the snapshot stays wrong, and the client sees success every time.
**Steps to reproduce**
Reproduced live on a hosted relay on 2026-08-03:
1. Archive an identity at a moment when the snapshot publish fails transiently (in our case the relay logged `failed to publish NIP-IA archival list`; the `archived_identities` row was committed).
2. Observe the divergence: identity `51c6e299…` had a DB row (and `is_archived` returned true), but was absent from the authoritative `kind:13535` snapshot (`buzz agents archived` verified against the raw event).
3. Send the same `kind:9035` archive request again — repeatedly. Every attempt is accepted (OK `true`), and none of them republish the snapshot.
4. The only client-side repair we found was a full unarchive → archive cycle: two `changed=true` transitions, which forces the delta + snapshot publishes to run again.
**Expected behavior**
The `kind:13535` snapshot should be repairable without destructively cycling the archive state. Two possible fixes (either alone would resolve it):
- **Republish on idempotent requests:** when `changed == false`, skip the delta (there was no state transition to describe) but still call `publish_nipia_archival_list`. The snapshot is a pure function of the `archived_identities` table, so republishing is always safe, and it makes "retry the request" an actual repair path.
- **Reconcile on read:** derive/verify the snapshot from the DB when it's served, so a lost publish self-heals.
**Secondary issue: side-effect failures are invisible to the requesting client.** The request event itself is accepted by ingest (https://github.com/block/buzz/blob/ac4fa13b8e4d947071d57deb6918dcf12bf74961/crates/buzz-relay/src/handlers/ingest.rs#L2300-L2304), so the client gets OK `true` even when the delta or snapshot publish failed — the errors exist only in relay logs. A client has no signal that the archive it just performed isn't reflected in the authoritative list. Worth considering whether publish failures should surface in the OK message (or at least be queryable), though that may deserve its own issue.
Related but distinct: #3848 covers snapshots lost to same-second `created_at` collisions between successive publishes. This issue is about a snapshot publish that failed outright and can never be retried because the retry path is gated on `changed`.
**Version and platform**
- Buzz version: main @ ac4fa13b8 (also observed on a hosted relay, 2026-08-03)
- OS: server-side (relay); client on Windows 11
**Logs / additional context**
Relay-side log lines for the failed publish (only visible server-side):
```
WARN failed to publish NIP-IA archival list
```
Client-side, every retry of the archive request returned:
```
["OK","",true,""]
```
with no change to the `kind:13535` snapshot.
Contributor guide
Assessment
This issue has not been assessed yet.