Note on provenance: this report and the underlying research were produced with AI agents
This needs someone with server access. No client change can work around it, and both apps are otherwise finished and waiting on it.
A primary QNS name is meant to replace a user's display name everywhere. It has never worked end to end in production for anyone, because the server refuses to accept one.
The error
POST /users/:addr/public-profile carrying a primary_username returns:
HTTP 400
qns primary username failed validation: qns lookup: Get "./": stopped after 10 redirects
The identical request without the field succeeds.
It is a configuration fault, not a rejected claim
The natural reading is that the server checked the claim and found it wanting. It did not — it never reached QNS.
Two publishes from the same account, seconds apart, differing only in the name:
| name sent |
resolves on QNS? |
result |
gatto |
no — /resolve/gatto is 404 |
HTTP 400, error above |
lamat |
yes — resolves, to a different address |
HTTP 400, byte-identical error |
A working ownership check has to tell those two apart. It does not, so the failure happens before the name is considered.
Get "./" is a Go HTTP client error on a relative URL: the QNS base URL the lookup is built from is empty or malformed, so the request resolves against itself and loops until the redirect limit.
So the validation can never pass, for any name, for any user, however legitimately they own it.
What this explains
- An account that genuinely owns a registered name, with a public profile, has no
primary_username in its published record — only bio, display_name, profile_image, signature, timestamp.
- The QNS primary-name tier, the rung that outranks a display name everywhere, has never once worked in production.
What is NOT broken
Stated because it narrows the fix:
- The v2 signing payload is fine — this is a 400 from the validation step with an explicit message, not a signature failure.
- Publishing without a name works — measured the same minute, a profile went 404 → 200 on a publish carrying no
primary_username.
- Un-electing works — it omits the field, taking the v1 route, which is accepted.
- The clients are not at fault — the request is signed and sent correctly. This is the server's own outbound request failing.
The work needed
Questions
- What is the validation meant to check — that the name resolves to the publishing address, or only that it exists?
- Is the QNS base URL an env var that is unset in this deployment?
- Should
primary_username be inside canonicalize, so a stale relay cannot strip it? Today it is covered by the v2 payload but is not part of the canonical signed profile fields shared with the space wire.
Client status, for context
Both apps are done and waiting. Mobile resolves and renders a .q on every name surface; desktop is at parity on the security-relevant parts. A name ending in .q can no longer forge the verified marker on either client (enforced in quorum-shared).
Worth noting the server's intent is good news: nothing in either client currently verifies that a claimed primary_username resolves back to the claimant, so a name transferred away but still elected locally would let two accounts render as the same .q. Once this lookup works, the server refuses that. Receiver-side verification is planned on the clients as defence in depth, but the server check is the stronger line.
Measured against api.quorummessenger.com on 2026-08-06 from a mobile dev build.
This needs someone with server access. No client change can work around it, and both apps are otherwise finished and waiting on it.
A primary QNS name is meant to replace a user's display name everywhere. It has never worked end to end in production for anyone, because the server refuses to accept one.
The error
POST /users/:addr/public-profilecarrying aprimary_usernamereturns:The identical request without the field succeeds.
It is a configuration fault, not a rejected claim
The natural reading is that the server checked the claim and found it wanting. It did not — it never reached QNS.
Two publishes from the same account, seconds apart, differing only in the name:
gatto/resolve/gattois 404lamatA working ownership check has to tell those two apart. It does not, so the failure happens before the name is considered.
Get "./"is a Go HTTP client error on a relative URL: the QNS base URL the lookup is built from is empty or malformed, so the request resolves against itself and loops until the redirect limit.So the validation can never pass, for any name, for any user, however legitimately they own it.
What this explains
primary_usernamein its published record — onlybio, display_name, profile_image, signature, timestamp.What is NOT broken
Stated because it narrows the fix:
primary_username.The work needed
GET /users/:addr/public-profileshowsprimary_username.Questions
primary_usernamebe insidecanonicalize, so a stale relay cannot strip it? Today it is covered by the v2 payload but is not part of the canonical signed profile fields shared with the space wire.Client status, for context
Both apps are done and waiting. Mobile resolves and renders a
.qon every name surface; desktop is at parity on the security-relevant parts. A name ending in.qcan no longer forge the verified marker on either client (enforced inquorum-shared).Worth noting the server's intent is good news: nothing in either client currently verifies that a claimed
primary_usernameresolves back to the claimant, so a name transferred away but still elected locally would let two accounts render as the same.q. Once this lookup works, the server refuses that. Receiver-side verification is planned on the clients as defence in depth, but the server check is the stronger line.Measured against
api.quorummessenger.comon 2026-08-06 from a mobile dev build.