dotnet/aspnetcore · error · Error

Cannot resolve '${url}'.

Error message

Cannot resolve '${url}'.

What it means

Thrown at HttpConnection.ts:676 inside _resolveUrl when the supplied url does not start with `http://` or `https://` AND `Platform.isBrowser` is false. Browsers can resolve relative URLs via an anchor tag (lines 684-688), but Node and other non-browser environments have no document to normalize against, so a non-absolute URL is unrecoverable.

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 294cab2f9b)

Solutions

  1. Pass a fully-qualified absolute URL in Node: `http://localhost:5000/hubs/chat`.
  2. Derive the URL from a base in Node: `new URL('/hubs/chat', process.env.BASE_URL).toString()`.
  3. For isomorphic code, branch on environment: in Node prepend the origin, in browser pass the relative path.

Example fix

// before (Node throws)
new HttpConnection('/hubs/chat');

// after
const base = process.env.HUB_BASE_URL || 'http://localhost:5000';
new HttpConnection(new URL('/hubs/chat', base).toString());
Defensive patterns

Strategy: validation

Validate before calling

function toAbsoluteUrl(maybeRelative) {
  if (/^https?:\/\//i.test(maybeRelative)) return maybeRelative;
  if (typeof window !== 'undefined') return new URL(maybeRelative, window.location.href).toString();
  throw new Error(`Cannot resolve '${maybeRelative}' outside a browser; provide an absolute URL`);
}
const absUrl = toAbsoluteUrl(config.hubUrl);

Type guard

function isAbsoluteHttpUrl(u: string): boolean {
  return /^https?:\/\//i.test(u);
}

Try / catch

// thrown synchronously from the constructor; wrap construction
let conn;
try { conn = new HttpConnection(url, options); }
catch (e) {
  if (/Cannot resolve/.test(String(e))) {
    conn = new HttpConnection(new URL(url, process.env.BASE_URL).toString(), options);
  } else throw e;
}

Prevention

When it happens

Trigger: In Node, calling `new HttpConnection('/hubs/chat')` or `new HttpConnection('hubs/chat')` or `'localhost:5000/hub'` (missing scheme). Browser builds accept these because window.document.createElement('a') resolves them, but Node builds hit the throw at line 676.

Common situations: Sharing the same code/config between browser and Node (SSR, Next.js getServerSideProps, SSR-rendered React); reading a relative path from env config and using it in a Node worker; forgetting the protocol when hardcoding a localhost URL in tests.

Related errors


AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06). Data as JSON: /api/errors/3898c18a3d66a2ee. Report an issue: GitHub.