dotnet/aspnetcore · error · Error
Cannot resolve ' '.
Error message
Cannot resolve '${url}'. What it means
Thrown by HttpConnection._resolveUrl when the supplied URL is relative (does not start with `http://` or `https://`) AND `Platform.isBrowser` is false. In a browser, the library normalizes relative URLs via an anchor tag; outside the browser there is no DOM to resolve against, so a base URL cannot be inferred and the call is rejected.
Solutions
- Pass a fully-qualified absolute URL (including scheme and host) when running outside a browser.
- Build the absolute URL from a base/host config variable rather than relying on document.location.
- If a base is required, prepend it explicitly: `${origin}/hub`.
Example fix
// before (Node runtime)
new HubConnectionBuilder().withUrl("/chat").build();
// after
new HubConnectionBuilder().withUrl("https://api.example.com/chat").build(); Defensive patterns
Strategy: validation
Validate before calling
function absoluteUrl(url: string): string {
if (/^https?:\/\//i.test(url)) return url;
const base = process.env.HUB_ORIGIN;
if (!base) throw new Error("Absolute URL required outside browser");
return new URL(url, base).href;
} Type guard
function isAbsoluteUrl(url: string): boolean {
return /^https?:\/\//i.test(url);
} Prevention
- Pass fully-qualified URLs in Node/SSR runtimes.
- Source the URL from a typed config with origin + path.
- Test the connection setup outside jsdom before shipping.
When it happens
Trigger: Running the signalr client in Node.js (or any non-browser runtime) and passing a relative path such as `/hub` or `hub` as the HubConnection URL. The same path works in a browser because the anchor-tag normalization path is taken, but in Node the `!Platform.isBrowser` guard fires.
Common situations: Server-side rendering, Electron main process, React Native, or a test runner (jsdom absent) where developers reuse a browser-style relative URL. Migrating code from browser to Node without adjusting the URL.
Related errors
- 'EventSource' is not supported in your environment.
- 'WebSocket' is not supported in your environment.
- No usable HttpClient found.
- The HubConnection url must be a valid url.
- The 'HubConnectionBuilder.withUrl' method must be called…
AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11).
Data as JSON: /api/errors/3898c18a3d66a2ee.
Report an issue: GitHub.
Appendix: source
Thrown at src/SignalR/clients/ts/signalr/src/HttpConnection.ts:676
this._connectionStarted = false;
try {
if (this.onclose) {
this.onclose(error);
}
} catch (e) {
this._logger.log(LogLevel.Error, `HttpConnection.onclose(${error}) threw error '${e}'.`);
}
}
}
private _resolveUrl(url: string): string {
// startsWith is not supported in IE
if (url.lastIndexOf("https://", 0) === 0 || url.lastIndexOf("http://", 0) === 0) {
return url;
}
if (!Platform.isBrowser) {
throw new Error(`Cannot resolve '${url}'.`);
}
// Setting the url to the href propery of an anchor tag handles normalization
// for us. There are 3 main cases.
// 1. Relative path normalization e.g "b" -> "http://localhost:5000/a/b"
// 2. Absolute path normalization e.g "/a/b" -> "http://localhost:5000/a/b"
// 3. Networkpath reference normalization e.g "//localhost:5000/a/b" -> "http://localhost:5000/a/b"
const aTag = window.document.createElement("a");
aTag.href = url;
this._logger.log(LogLevel.Information, `Normalizing '${url}' to '${aTag.href}'.`);
return aTag.href;
}
private _resolveNegotiateUrl(url: string): string {
const negotiateUrl = new URL(url);
if (negotiateUrl.pathname.endsWith('/')) {View on GitHub (pinned to 3600ca084e)