{"record":{"id":"41936046fb5013b9","repo":"agalwood/Motrix","slug":"plugin-http-invalid-url","errorCode":"plugin.http.invalid_url","errorMessage":"Invalid URL: ${raw}","messagePattern":"Invalid URL: (.+?)","errorType":"validation","errorClass":"HttpError","httpStatus":null,"severity":"error","filePath":"src/core/plugin/capabilities/http.ts","lineNumber":136,"sourceCode":"const HARD_MAX_BODY_BYTES = 200 * 1024 * 1024 // 200 MB\n\nconst MAX_REDIRECTS = 10\n\nconst ALLOWED_SCHEMES = new Set(['http:', 'https:'])\n\n// Shared dispatcher for non-proxied requests; per-call ProxyAgent is built\n// fresh when `opts.proxy` is provided.\nconst sharedAgent = new Agent()\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction parseUrl(raw: string): URL {\n  try {\n    return new URL(raw)\n  } catch {\n    throw new HttpError('plugin.http.invalid_url', `Invalid URL: ${raw}`)\n  }\n}\n\nfunction checkScheme(parsed: URL): void {\n  if (!ALLOWED_SCHEMES.has(parsed.protocol)) {\n    throw new HttpError(\n      'plugin.http.scheme_not_allowed',\n      `URL scheme '${parsed.protocol}' is not allowed; use http: or https:`\n    )\n  }\n}\n\nfunction clampTimeout(ms: number | undefined, defaultMs: number): number {\n  // Reject non-finite values (NaN/Infinity) — http.get/post reach this with\n  // unvalidated opts, and Math.min(MAX, NaN) is NaN, disabling the timeout.\n  if (ms === undefined || !Number.isFinite(ms)) return defaultMs\n  return Math.max(MIN_TIMEOUT_MS, Math.min(MAX_TIMEOUT_MS, ms))\n}","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/agalwood/Motrix/blob/1a708ee57746c434e2c67a44bbf0906a976afea4/src/core/plugin/capabilities/http.ts#L118-L154","documentation":"Thrown by the http capability's internal `parseUrl(raw)` helper when `new URL(raw)` throws — i.e. the input is not a parseable absolute URL (missing scheme, malformed host, stray characters). It is the earliest validation in the request pipeline; scheme-allowlist and body/timeout checks run only after this passes. Code is `plugin.http.invalid_url`.","triggerScenarios":"Calling the http request API with a string like `'example.com/path'` (no scheme), `'ht tp://x'` (whitespace), `'localhost:8080'` (interpreted as port on a scheme-less URL), or a value that is not a string at all. Anything the WHATWG URL parser rejects lands here.","commonSituations":"User-supplied URL missing `https://`; env var loaded with trailing whitespace/newline; concatenated URL with an undefined segment producing `undefined/api`; URL built from a port-only string.","solutions":["Validate with `new URL(raw)` yourself before calling the http API and reject bad input with a clear error.","Normalize input: trim whitespace and prepend `https://` only when a scheme is genuinely missing AND the host is valid.","Type-check that the url field is a non-empty string at the trust boundary.","Log the offending raw value (carefully) when surfacing the error so the source is obvious."],"exampleFix":"// before\nawait http.request({ url: userInput }) // 'example.com' -> throws\n\n// after\nfunction normalizeUrl(raw: string): string {\n  const u = new URL(raw.startsWith('http') ? raw : `https://${raw}`)\n  if (!/^(http:|https:)$/.test(u.protocol)) throw new Error('bad url')\n  return u.toString()\n}\nawait http.request({ url: normalizeUrl(userInput) })","handlingStrategy":"validation","validationCode":"function ensureUrl(raw: string): string {\n  if (typeof raw !== 'string' || raw.trim().length === 0) {\n    throw new Error('url is required')\n  }\n  const u = new URL(raw) // throws synchronously if malformed\n  if (!/^https?:$/.test(u.protocol)) throw new Error(`scheme not allowed: ${u.protocol}`)\n  return u.toString()\n}","typeGuard":"function isInvalidUrl(e: unknown): boolean {\n  return e instanceof Error && (e as HttpError).code === 'plugin.http.invalid_url'\n}","tryCatchPattern":"try {\n  await http.request({ url: raw })\n} catch (e) {\n  if (isInvalidUrl(e)) { /* surface a clear 'bad URL' error to the caller */ }\n  else throw e\n}","preventionTips":["Validate with new URL() yourself before calling the http API.","Trim whitespace from URL env vars and config values.","Reject scheme-less URLs at the input boundary rather than coercing silently."],"tags":["http","url","validation","input-validation"],"backgroundTag":null,"analyzedSha":"1a708ee57746c434e2c67a44bbf0906a976afea4","analyzedAt":"2026-08-12T16:18:09.346Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}