agalwood/Motrix · error · HttpError

plugin.http.invalid_url

plugin.http.invalid_url

Error message

Invalid URL: ${raw}

What it means

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`.

Source

Thrown at src/core/plugin/capabilities/http.ts:136

const HARD_MAX_BODY_BYTES = 200 * 1024 * 1024 // 200 MB

const MAX_REDIRECTS = 10

const ALLOWED_SCHEMES = new Set(['http:', 'https:'])

// Shared dispatcher for non-proxied requests; per-call ProxyAgent is built
// fresh when `opts.proxy` is provided.
const sharedAgent = new Agent()

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

function parseUrl(raw: string): URL {
  try {
    return new URL(raw)
  } catch {
    throw new HttpError('plugin.http.invalid_url', `Invalid URL: ${raw}`)
  }
}

function checkScheme(parsed: URL): void {
  if (!ALLOWED_SCHEMES.has(parsed.protocol)) {
    throw new HttpError(
      'plugin.http.scheme_not_allowed',
      `URL scheme '${parsed.protocol}' is not allowed; use http: or https:`
    )
  }
}

function clampTimeout(ms: number | undefined, defaultMs: number): number {
  // Reject non-finite values (NaN/Infinity) — http.get/post reach this with
  // unvalidated opts, and Math.min(MAX, NaN) is NaN, disabling the timeout.
  if (ms === undefined || !Number.isFinite(ms)) return defaultMs
  return Math.max(MIN_TIMEOUT_MS, Math.min(MAX_TIMEOUT_MS, ms))
}

View on GitHub (pinned to 1a708ee577)

Solutions

  1. Validate with `new URL(raw)` yourself before calling the http API and reject bad input with a clear error.
  2. Normalize input: trim whitespace and prepend `https://` only when a scheme is genuinely missing AND the host is valid.
  3. Type-check that the url field is a non-empty string at the trust boundary.
  4. Log the offending raw value (carefully) when surfacing the error so the source is obvious.

Example fix

// before
await http.request({ url: userInput }) // 'example.com' -> throws

// after
function normalizeUrl(raw: string): string {
  const u = new URL(raw.startsWith('http') ? raw : `https://${raw}`)
  if (!/^(http:|https:)$/.test(u.protocol)) throw new Error('bad url')
  return u.toString()
}
await http.request({ url: normalizeUrl(userInput) })
Defensive patterns

Strategy: validation

Validate before calling

function ensureUrl(raw: string): string {
  if (typeof raw !== 'string' || raw.trim().length === 0) {
    throw new Error('url is required')
  }
  const u = new URL(raw) // throws synchronously if malformed
  if (!/^https?:$/.test(u.protocol)) throw new Error(`scheme not allowed: ${u.protocol}`)
  return u.toString()
}

Type guard

function isInvalidUrl(e: unknown): boolean {
  return e instanceof Error && (e as HttpError).code === 'plugin.http.invalid_url'
}

Try / catch

try {
  await http.request({ url: raw })
} catch (e) {
  if (isInvalidUrl(e)) { /* surface a clear 'bad URL' error to the caller */ }
  else throw e
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12). Data as JSON: /api/errors/41936046fb5013b9. Report an issue: GitHub.