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

  1. Pass a fully-qualified absolute URL (including scheme and host) when running outside a browser.
  2. Build the absolute URL from a base/host config variable rather than relying on document.location.
  3. 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

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


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)