Note
Stale Lists and Dark Outboxes: When NIP-65 Metadata Lies by Age or Uptime
NIP-65 kind:10002 is discovery, not authority — stale relay lists and dark outboxes are the real failure modes; client merge is not consensus.
2026-09-21 · nostr, nip-65, relays, protocol

Stale Lists and Dark Outboxes: When NIP-65 Metadata Lies by Age or Uptime
NIP-65 taught the useful half of the story: a signed kind:10002 list tells clients where an author generally writes and where they generally read mentions. That is discovery. It is not authority, and it is not consensus.
A live Primal-thread reply on CryptoDecentral’s NIP-65 post put the sharper cut: outbox lists are availability preferences, not network votes. Relays go dark. Lists go stale. Clients merge what they can see. None of that produces a global ordered feed — and on Nostr that missing total order is by design, not a bug waiting for a patch.
This sequel is protocol literacy about those failure modes. It assumes you already know the outbox/inbox routing rules from the companion note.
Discovery is not authority
NIP-65’s job is narrow. The draft optional NIP defines a replaceable kind:10002 whose r tags advertise write and read relays. Clients SHOULD fetch an author’s notes from their write relays, drop mentions on their read relays, and republish the author’s 10002 alongside content so the preference travels.
That is a routing hint, signed by the pubkey. It answers where should I look first? — not which events are network-true, which timeline is canonical, which relay is “official,” or whether those URLs are still alive.
Authority language creeps in when people say “the authoritative relay list.” Soft clarification, from NIP-01’s replaceable-event rules: for kinds in the replaceable range (10000 <= n < 20000, plus 0 and 3), relays MUST keep only the latest event per (pubkey, kind) — older versions MAY be discarded. Tie-break on equal created_at: lowest id (lexical). So “authoritative list” for kind:10002 means latest-wins for that pubkey and kind, as observed by a given relay or client. It does not mean the network agreed. Two honest relays can temporarily hold different versions; two clients can merge different supersets. Latest-wins is a local retention rule, not BFT consensus.
Treat 10002 as preference metadata with a replaceable clock. Prefer it when fresh and confirmed. Do not crown it as ground truth.
How metadata lies: age and uptime
Two ordinary failure modes dominate once clients actually follow NIP-65.
1. Stale kind:10002 lists
Replaceable events do not expire by protocol. A list published months ago remains the latest if the author never signed a newer one. Between publication and observation, reality moves:
- The author migrates write relays and forgets to republish
10002. - A client caches an old list and reuses it without re-fetching from indexers or gossip.
- Indexer-ish relays still serve an older copy while a newer one exists elsewhere; bootstrap hit the wrong socket first.
- Equal timestamps produce the NIP-01 lexical
idtie-break — rare, but a reminder that “latest” is a defined rule, not mysticism.
Symptoms look like product bugs: empty author feeds, replies that never arrive, “they’re online but silent.” Often the client is faithfully querying yesterday’s outbox.
Mitigations are mechanical: re-query kinds:[10002] on a schedule; prefer higher created_at across sources; when lists disagree, see which write relays actually hold recent notes from that pubkey; republish your own 10002 when relays change (and let clients spread it per NIP-65 discoverability).
2. Outboxes going dark
A fresh list can still point at dead sockets. Relays shut down, rate-limit, require auth the client cannot satisfy, drop history, or simply fail TLS. NIP-65 does not require liveness proofs. An r tag is a URL preference, not a heartbeat.
Dark outbox behaviour:
- Followers open the advertised write relays and get nothing — or
CLOSED/ connection errors. - Mentions still land on advertised read relays that are up, so the author sees tags while followers see a ghost profile.
- Clients that never fall back to tag hints (
e/prelay hints in NIP-01), follow-graph gossip, or previously working relays strand the user on a tombstone preference.
Routing remains solvable: treat 10002 as the first preference set, probe reachability, demote dark URLs for a cooldown, and keep secondary discovery paths. Preference failing open is correct for gossip; UX that pretends the list is always live is not. Keep lists small (NIP-65: about 2–4 relays per category) so completeness does not hide tombstones.
Client merge is not consensus
Clients routinely union events from several relays: author’s write set, mention targets, bootstrap indexers, local cache. That merge is availability aggregation. It maximises what this client can show. It does not produce a unique global sequence of all notes.
There is no shared mempool clock. Relays accept and store independently. created_at is author-chosen (within whatever policy a relay enforces). EOSE ends stored replay for a subscription; it is not a finality gadget. Two clients following the same pubkeys can disagree on presence, order, and completeness — indefinitely — without anyone “cheating.”
That is the intentional asymmetry: routing is an engineering problem; total ordering is not a solvable network-wide invariant under Nostr’s threat model. Signed events authenticate content; they do not mint a ledger of when everyone saw what. Social clients invent local sort keys — UI policy, not consensus. If you need total order, you want a chain, a sequenced log, or one operator’s database. Nostr chose gossip + signatures. NIP-65 directs the gossip; treating the ordering gap as a defect invites “just use the one big relay” cosplay.
What clients can still do well
Concrete, non-hype behaviours that respect the model:
- Probe before trust. After loading
10002, check that write relays accept connections and return recent notes for that author when expected. - Refresh replaceables. Periodically re-fetch
kind:10002(and other replaceables you depend on). Cache with TTL; do not eternalise first contact. - Fall back without flooding. If outboxes are dark, use NIP-01 relay hints on tags, last-known-good relays, and small secondary sets — not “connect to the entire public list.”
- Separate layers. NIP-11 still answers what a relay claims it can do. NIP-65 answers which relays this pubkey prefers. Liveness answers whether those sockets work today. Confusing any two produces empty screens.
- Publish the preference when it changes. Authors who rotate infrastructure without a new
10002are asking the network to remember a lie.
When relays vanish under pressure, stale routing metadata is a quieter failure than overt takedown: readers think the author left; the author thinks the network ghosted them. Age-and-uptime literacy keeps speech paths repairable without recentralising on one branded socket.
What this is not
This note is not a ranked relay directory, a client install guide, or a promise that “correct NIP-65 fixes feeds forever.” It does not redefine replaceable events as network consensus. It does not claim total ordering can be bolted onto gossip without changing the architecture. It does not advise paying relays as products or investments, pitch custody flows, or treat outbox URLs as assets. It does not teach evasion of lawful process. It does not replace signature verification or reading live relay behaviour after NIP-11 claims.
Educational takeaway: NIP-65 fixes directed discovery; it does not mint authority or a global clock. Stale lists and dark outboxes are the expected edge of preference metadata. Routing you can harden. Total order you should stop expecting.
Related on CryptoDecentral
- NIP-65: Relay Lists, Outbox, and Inbox — Routing Beyond One Home Relay
- Nostr pillar
- NIP-11: How Nostr Relays Advertise What They Can Do
- Network metrics
Further reading (primary)
Sources
- https://raw.githubusercontent.com/nostr-protocol/nips/master/65.md
- https://github.com/nostr-protocol/nips/blob/master/65.md
- https://nips.nostr.com/65
- https://raw.githubusercontent.com/nostr-protocol/nips/master/01.md
- https://github.com/nostr-protocol/nips/blob/master/01.md
- https://raw.githubusercontent.com/nostr-protocol/nips/master/README.md