{"id":"a51edce538cc5251","repo":"sindresorhus/got","slug":"url-must-not-start-with-a-slash","errorCode":null,"errorMessage":"`url` must not start with a slash","messagePattern":"`url` must not start with a slash","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"source/core/options.ts","lineNumber":2106,"sourceCode":"\t// The query string is overridden by `searchParams`\n\tawait got('https://example.com/?query=a b', {searchParams: {query: 'a b'}}); //=> https://example.com/?query=a+b\n\t```\n\t*/\n\tget url(): string | URL | undefined {\n\t\treturn this.#internals.url;\n\t}\n\n\tset url(value: string | URL | undefined) {\n\t\tassertAny('url', [is.string, is.urlInstance, is.undefined], value);\n\n\t\tif (value === undefined) {\n\t\t\tthis.#internals.url = undefined;\n\t\t\ttrackStateMutation(this.#trackedStateMutations, 'url');\n\t\t\treturn;\n\t\t}\n\n\t\tif (is.string(value) && value.startsWith('/')) {\n\t\t\tthrow new Error('`url` must not start with a slash');\n\t\t}\n\n\t\tconst valueString = value.toString();\n\n\t\tif (\n\t\t\tis.string(value)\n\t\t\t&& !this.prefixUrl\n\t\t\t&& hasHttpProtocolWithoutSlashes(valueString)\n\t\t) {\n\t\t\tthrow new Error('`url` protocol must be followed by `//`');\n\t\t}\n\n\t\t// Detect if URL is already absolute.\n\t\tconst isAbsolute = isAbsoluteUrl(value);\n\t\tassertRelativeUrlIfNeeded(this, value);\n\n\t\t// Only concatenate prefixUrl if the URL is relative\n\t\tconst urlString = isAbsolute ? valueString : `${this.prefixUrl as string}${valueString}`;","sourceCodeStart":2088,"sourceCodeEnd":2124,"githubUrl":"https://github.com/sindresorhus/got/blob/e3924aa1e53a6ca3eb93a43618ce532442a89b40/source/core/options.ts#L2088-L2124","documentation":"Thrown by the `url` setter when the URL string begins with `/`. Got forbids leading slashes in `input`/`url` to remove the ambiguity of how it combines with `prefixUrl` (browser-style path replacement vs. concatenation). The rule is enforced consistently whether or not `prefixUrl` is set.","triggerScenarios":"Calling `got('/users')` (no prefixUrl, leading slash), `got('/users', {prefixUrl: 'https://api.com'})` (leading slash with prefixUrl), or building a path string that starts with `/` and passing it positionally or as `options.url`.","commonSituations":"Switching from `fetch`/`axios` where leading-slash paths are idiomatic; building paths via template literals like `` `/${route}` ``; assuming `prefixUrl` behaves like a base URL that strips leading slashes.","solutions":["Drop the leading slash from the path: `got('users', {prefixUrl: 'https://api.com'})`.","If you have no prefixUrl and want an absolute URL, pass the full URL including protocol: `got('https://api.com/users')`.","Strip leading slashes programmatically: `path.replace(/^\\/+/, '')` before passing."],"exampleFix":"// before\nconst instance = got.extend({prefixUrl: 'https://api.example.com'});\nawait instance('/users');\n// after\nconst instance = got.extend({prefixUrl: 'https://api.example.com'});\nawait instance('users');","handlingStrategy":"validation","validationCode":"function normalizePath(path) {\n  if (typeof path === 'string' && path.startsWith('/')) {\n    throw new Error(`Got input must not start with '/': ${path}`);\n  }\n  return path;\n}","typeGuard":"function isRelativePathWithoutLeadingSlash(v: unknown): boolean {\n  return typeof v === 'string' && !v.startsWith('/') && !/^https?:\\/\\//i.test(v);\n}","tryCatchPattern":null,"preventionTips":["Convention: with `prefixUrl`, always pass paths without a leading slash.","Sanitize route builders: `route.replace(/^\\/+/, '')`.","Add a lint rule or helper that strips leading slashes before Got calls."],"tags":["options","url","prefix-url","validation"],"analyzedSha":"e3924aa1e53a6ca3eb93a43618ce532442a89b40","analyzedAt":"2026-08-03T19:22:24.770Z","schemaVersion":2}