{"record":{"id":"152018cb828a2e8e","repo":"dotnet/aspnetcore","slug":"no-url-defined","errorCode":null,"errorMessage":"No url defined.","messagePattern":"No url defined\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/SignalR/clients/ts/signalr/src/FetchHttpClient.ts","lineNumber":69,"sourceCode":"            // Node needs EventListener methods on AbortController which our custom polyfill doesn't provide\n            this._abortControllerType = requireFunc(\"abort-controller\");\n        } else {\n            this._abortControllerType = AbortController;\n        }\n    }\n\n    /** @inheritDoc */\n    public async send(request: HttpRequest): Promise<HttpResponse> {\n        // Check that abort was not signaled before calling send\n        if (request.abortSignal && request.abortSignal.aborted) {\n            throw new AbortError();\n        }\n\n        if (!request.method) {\n            throw new Error(\"No method defined.\");\n        }\n        if (!request.url) {\n            throw new Error(\"No url defined.\");\n        }\n\n        const abortController = new this._abortControllerType();\n\n        let error: any;\n        // Hook our abortSignal into the abort controller\n        if (request.abortSignal) {\n            request.abortSignal.onabort = () => {\n                abortController.abort();\n                error = new AbortError();\n            };\n        }\n\n        // If a timeout has been passed in, setup a timeout to call abort\n        // Type needs to be any to fit window.setTimeout and NodeJS.setTimeout\n        let timeoutId: any = null;\n        if (request.timeout) {\n            const msTimeout = request.timeout!;","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/3600ca084e9c8b5f4174fc5e747f4c52d2100806/src/SignalR/clients/ts/signalr/src/FetchHttpClient.ts#L51-L87","documentation":"FetchHttpClient.send throws if the HttpRequest has no url. Without a destination, fetch() cannot proceed, so the client fails fast rather than emitting a cryptic fetch error.","triggerScenarios":"Calling httpClient.send with a request object whose url is empty/undefined. Typically a result of building a request from an empty withUrl configuration, or a templated URL that resolved to undefined.","commonSituations":"HubConnectionBuilder().withUrl(\"\") or withUrl(undefined) where the URL was supposed to come from config/env. URL template that didn't interpolate. Manually invoking httpClient.send for a custom call and forgetting the url.","solutions":["Pass a fully-qualified, non-empty URL string to withUrl().","Validate the URL is truthy before constructing the connection: if (!hubUrl) throw new Error(\"hubUrl missing\").","Check that any environment variable feeding the URL is set at runtime."],"exampleFix":"// before\nconst url = process.env.HUB_URL;\nconst conn = new signalR.HubConnectionBuilder().withUrl(url).build();\n\n// after\nconst url = process.env.HUB_URL;\nif (!url) throw new Error(\"HUB_URL not set\");\nconst conn = new signalR.HubConnectionBuilder().withUrl(url).build();","handlingStrategy":"validation","validationCode":"if (!url) throw new Error(\"withUrl requires a non-empty URL\");\nnew URL(url); // throws on malformed URLs too\nnew signalR.HubConnectionBuilder().withUrl(url).build();","typeGuard":"function isNonEmptyUrl(u: unknown): u is string {\n  return typeof u === \"string\" && u.length > 0 && /^https?:\\/\\//.test(u);\n}","tryCatchPattern":"try { await connection.start(); }\ncatch (e) {\n  if (e instanceof Error && e.message === \"No url defined.\") {\n    throw new Error(\"Configuration error: hub URL was empty.\");\n  }\n  throw e;\n}","preventionTips":["Validate the hub URL is set (env var present, non-empty) at app startup.","Use new URL(url) to fail fast on malformed URLs.","Default URLs in config rather than leaving them undefined."],"tags":["http","request-validation","url","fetch"],"backgroundTag":null,"analyzedSha":"3600ca084e9c8b5f4174fc5e747f4c52d2100806","analyzedAt":"2026-08-11T16:32:30.678Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}