What happens
Verdict pages often say "Not in the registry." for servers that are in the registry and have been reviewed.
Example: /r/sxf1_87f33b89087548123aee2da4efcffd92b562360037f5c0fab6560e71a78d6121
The API has this entry and answers fine:
GET arkiv-surex-api.vercel.app/v1/entry/sxf1_87f33b89…
→ 200 state=clean @modelcontextprotocol/server-gitlab tier C
It is not one bad entry. Every fingerprint on the site can do this.
Why
Two separate bugs stack up.
1. The fetch times out
apps/web/lib/api.ts:39 gives the fetch 2500ms. When the API function is cold it takes longer than that. The fetch aborts, so getEntry treats the registry as unreachable and falls back to local fixtures (api.ts:186). There is no fixture for a real fingerprint, so it returns null, and the page shows "Not in the registry."
Measured on the live site, same URL, cache-busted:
| Test |
Result |
| 12 loads in a row |
first 3 failed, next 9 rendered |
| Wait 45s, load again |
failed |
| Local dev against the same prod API |
rendered every time |
2. The page hides the reason
apps/web/app/r/[fp]/page.tsx:50-69 — the "no entry" branch returns before IllustrativeBanner and never checks origin === 'fixture'. The two branches below it (lines 84 and 94) both do check.
So on /r/, "we could not reach the registry" looks exactly like "nobody has reviewed this server." A reviewed, clean server is shown to the user as unknown.
/d/[fp] handles this correctly (line 58). That page prints the real reason, which is how we found it:
REGISTRY UNREACHABLE: The operation was aborted due to timeout
This is the one thing the code says it will not do. The header in api.ts says the three outcomes are "kept distinct", and commit 9269631 is titled "the read path — and it refuses to turn 'could not look' into 'found nothing'". On this route it turns one into the other.
Fix
- In the "no entry" branch of
r/[fp]/page.tsx, when result.origin === 'fixture', show the REGISTRY UNREACHABLE banner instead of "Not in the registry." Do this one first — right now the page tells the user the opposite of the truth.
- Raise
TIMEOUT_MS for the page. 2500ms is inherited from the gate budget, which guards every tool call. A page render can afford to wait longer.
- Look at the API cold start behind both.
Ruled out
- Routing — HTTP 200,
x-matched-path: /r/[fp]
- Env —
NEXT_PUBLIC_SUREX_API is inlined correctly as the right API
- Stale deploy —
main and the working branch differ only in comments
- Parsing —
parseVerdictHead accepts the real payload
- Flaky API — 10/10 requests at 0.3-0.5s
What happens
Verdict pages often say "Not in the registry." for servers that are in the registry and have been reviewed.
Example:
/r/sxf1_87f33b89087548123aee2da4efcffd92b562360037f5c0fab6560e71a78d6121The API has this entry and answers fine:
It is not one bad entry. Every fingerprint on the site can do this.
Why
Two separate bugs stack up.
1. The fetch times out
apps/web/lib/api.ts:39gives the fetch 2500ms. When the API function is cold it takes longer than that. The fetch aborts, sogetEntrytreats the registry as unreachable and falls back to local fixtures (api.ts:186). There is no fixture for a real fingerprint, so it returnsnull, and the page shows "Not in the registry."Measured on the live site, same URL, cache-busted:
2. The page hides the reason
apps/web/app/r/[fp]/page.tsx:50-69— the "no entry" branch returns beforeIllustrativeBannerand never checksorigin === 'fixture'. The two branches below it (lines 84 and 94) both do check.So on
/r/, "we could not reach the registry" looks exactly like "nobody has reviewed this server." A reviewed, clean server is shown to the user as unknown./d/[fp]handles this correctly (line 58). That page prints the real reason, which is how we found it:This is the one thing the code says it will not do. The header in
api.tssays the three outcomes are "kept distinct", and commit9269631is titled "the read path — and it refuses to turn 'could not look' into 'found nothing'". On this route it turns one into the other.Fix
r/[fp]/page.tsx, whenresult.origin === 'fixture', show theREGISTRY UNREACHABLEbanner instead of "Not in the registry." Do this one first — right now the page tells the user the opposite of the truth.TIMEOUT_MSfor the page. 2500ms is inherited from the gate budget, which guards every tool call. A page render can afford to wait longer.Ruled out
x-matched-path: /r/[fp]NEXT_PUBLIC_SUREX_APIis inlined correctly as the right APImainand the working branch differ only in commentsparseVerdictHeadaccepts the real payload