{"record":{"id":"b7e0599eeae851e7","repo":"upstash/context7","slug":"context7-base-url-must-not-contain-a-query-string-or","errorCode":null,"errorMessage":"Context7 base URL must not contain a query string or fragment","messagePattern":"Context7 base URL must not contain a query string or fragment","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cli/src/setup/deployment.ts","lineNumber":28,"sourceCode":"\nexport function normalizeDeploymentBaseUrl(input?: string): string {\n  const raw = input?.trim() || DEFAULT_CONTEXT7_BASE_URL;\n  let url: URL;\n\n  try {\n    url = new URL(raw);\n  } catch {\n    throw new Error(`Invalid Context7 base URL: ${raw}`);\n  }\n\n  if (url.protocol !== \"http:\" && url.protocol !== \"https:\") {\n    throw new Error(\"Context7 base URL must use http:// or https://\");\n  }\n  if (url.username || url.password) {\n    throw new Error(\"Context7 base URL must not contain credentials\");\n  }\n  if (url.search || url.hash) {\n    throw new Error(\"Context7 base URL must not contain a query string or fragment\");\n  }\n\n  url.pathname = url.pathname.replace(/\\/+$/, \"\") || \"/\";\n  const normalized = url.toString().replace(/\\/$/, \"\");\n  if (url.pathname.endsWith(\"/mcp\") || url.pathname.endsWith(\"/api\")) {\n    throw new Error(\"Pass the Context7 deployment root, without /mcp or /api\");\n  }\n  return normalized;\n}\n\nexport function resolveSetupDeployment(input?: string): SetupDeployment {\n  const baseUrl = normalizeDeploymentBaseUrl(input);\n  return baseUrl === DEFAULT_CONTEXT7_BASE_URL\n    ? { kind: \"hosted\", baseUrl: DEFAULT_CONTEXT7_BASE_URL }\n    : { kind: \"custom\", baseUrl };\n}\n\nexport function getMcpUrl(deployment: SetupDeployment, auth: AuthOptions): string {","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/upstash/context7/blob/4416fb855b8f752be735e34f943b5d0762701aad/packages/cli/src/setup/deployment.ts#L10-L46","documentation":"Thrown by normalizeDeploymentBaseUrl when the URL contains a query string (?) or fragment (#). A deployment base URL must be a clean origin-plus-path root because the CLI appends its own endpoints (/mcp, /api/...) to it.","triggerScenarios":"normalizeDeploymentBaseUrl receives a URL with url.search or url.hash non-empty, e.g. 'https://host?env=prod' or 'https://host#section'.","commonSituations":"Copying a URL straight from a browser address bar including tracking params or an anchor; appending an API key as a query parameter.","solutions":["Remove everything from '?' or '#' onward, keeping only scheme://host[:port]/path-root.","Move any parameters (e.g. tokens) into proper configuration instead of the URL.","Omit the argument to use the hosted default."],"exampleFix":"// before\nctx7 setup --url https://my-onprem.internal?token=abc#mcp\n\n// after\nctx7 setup --url https://my-onprem.internal","handlingStrategy":"validation","validationCode":"function urlIsClean(raw: string): boolean {\n  try {\n    const u = new URL(raw);\n    return !u.search && !u.hash;\n  } catch { return false; }\n}","typeGuard":null,"tryCatchPattern":"try {\n  const dep = resolveSetupDeployment(input);\n} catch (e) {\n  if ((e as Error).message.includes('query string or fragment')) {\n    console.error('Remove ?query and #fragment from the base URL.');\n  }\n}","preventionTips":["When copying from a browser address bar, delete everything from '?' onward.","Pass parameters via environment/config, never in the base URL.","Sanitize pasted URLs (strip query/fragment) in wrapper scripts."],"tags":["url","validation","configuration","cli"],"backgroundTag":"invalid-url-format","analyzedSha":"4416fb855b8f752be735e34f943b5d0762701aad","analyzedAt":"2026-09-16T20:28:07.148Z","contentChangedAt":"2026-09-16T20:28:07.148Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}