Repository navigation
[BUG]: Invalid info.relay_url passes validation but then breaks every HTTP request #824
Description
Summary
If info.relay_url is set to something that isn't a valid URL, the relay still starts and validateSettings() reports no problems. But after that, every HTTP request fails with a 500 error, including the Admin Console.
What I did
I set info.relay_url to nostream.example.com (no wss:// in front) in .nostr/settings.yaml and started the relay.
What happened
validateSettings()returned no issues.- Every HTTP request returned
500 Internal Server ErrorwithTypeError: Invalid URL. - This included
/,/healthz,/readyz,/admin,/admin/dashboardand/admin/login.
Because the Admin Console is down too, the setting can't be fixed from the UI. It has to be edited in the file by hand.
Why it happens
validateSettings()only checks thatrelay_urlis set (src/utils/settings-config.ts, lines 595-597). It doesn't check that it's a valid URL.- A middleware in
src/factories/web-app-factory.ts(line 21) runsnew URL(settings.info.relay_url)on every request. It runs before the router, so every route is affected. The call isn't wrapped in a try/catch.
getPublicHttpOrigin() in src/utils/http.ts already wraps the same call in a try/catch, so this middleware looks like it was just missed.
Steps to reproduce
- Check out
242a3001d77149e4d70151ec03060c4ef44a1547(3.4.0, same as upstream main when I tested). - Set
info.relay_url: nostream.example.comin.nostr/settings.yaml. - Start the relay.
- Run
curl -i http://localhost:8008/.
Expected behavior
validateSettings() should reject a relay_url that isn't a valid absolute URL, with a clear message on info.relay_url.
Logs
TypeError: Invalid URL
at new URL (node:internal/url:828:25)
at .../dist/src/factories/web-app-factory.js:22:26
at Layer.handle [as handle_request] (.../express@4.22.1/node_modules/express/lib/router/layer.js:95:5)
GET / -> 500
GET /healthz -> 500
GET /readyz -> 500
GET /admin -> 500
GET /admin/login -> 500
Environment
- nostream 3.4.0, commit
242a3001d77149e4d70151ec03060c4ef44a1547 - Node.js v24.9.0, pnpm 10.33.0
- Windows 11, standalone Node (no Docker)
Suggested fix
A plain try { new URL(...) } isn't enough, because new URL('localhost:8008') doesn't throw. It treats localhost: as the scheme and leaves the host empty. So the check should look at the protocol and the host:
if (!settings.info?.relay_url) {
issues.push({ path: 'info.relay_url', message: 'relay_url is required' })
} else {
try {
const parsed = new URL(settings.info.relay_url)
if (!['ws:', 'wss:', 'http:', 'https:'].includes(parsed.protocol)) {
issues.push({ path: 'info.relay_url', message: 'relay_url must use ws, wss, http, or https protocol' })
} else if (!parsed.host) {
issues.push({ path: 'info.relay_url', message: 'relay_url must include a valid host' })
}
} catch {
issues.push({ path: 'info.relay_url', message: 'relay_url must be a valid absolute URL' })
}
}
I tried this locally: nostream.example.com, localhost:8008 and ftp://x.com are rejected, while wss://nostream.example.com and the default settings file still pass. The existing settings-config and cli/config unit tests pass too.
I'm happy to open a PR with tests if this approach works for you.
Activity
chappie-daemon commentedon Oct 15, 2026
Thanks @tarunagnihotri534 for the excellent report — the diagnosis was spot-on, including the
new URL('localhost:8008')host quirk. A fix is up in #825:validateSettings()now rejects a relay_url that isn't a valid absolute URL, has no host, or uses a non-ws/wss/http/https protocol. One small deviation from your snippet: the host check runs before the protocol check, solocalhost:8008gets the accurate "must include a valid host" message instead of a misleading protocol complaint. Your four repro cases are covered as tests. Thanks again!