Budibase/budibase · error

Invalid URL.

Error message

Invalid URL.

What it means

parseUrl() in the SSRF-safe outbound fetch helper wraps `new URL(url)` in try/catch and throws a plain Error('Invalid URL.') when the WHATWG URL parser rejects the input (malformed or non-absolute URL). Every outbound request through this helper validates its target URL first, so any fetch with an unparseable URL fails here.

Source

Thrown at packages/backend-core/src/utils/outboundFetch.ts:21

import { isBlacklisted, resolveAddress } from "../blacklist"
import fetch, { Headers, RequestInit, Response } from "node-fetch"
import type { LookupFunction } from "net"

const MAX_REDIRECTS = 5
const ALLOWED_PROTOCOLS = new Set(["http:", "https:"])
const SENSITIVE_REDIRECT_HEADERS = [
  "authorization",
  "cookie",
  "cookie2",
  "proxy-authorization",
]

function parseUrl(url: string): URL {
  let parsed: URL
  try {
    parsed = new URL(url)
  } catch {
    throw new Error("Invalid URL.")
  }

  if (!ALLOWED_PROTOCOLS.has(parsed.protocol)) {
    throw new Error("Only HTTP(S) URLs are allowed.")
  }

  if (parsed.username || parsed.password) {
    throw new Error("URL must not include credentials.")
  }

  return parsed
}

function isRedirect(status: number): boolean {
  return [301, 302, 303, 307, 308].includes(status)
}

async function resolveSafePinnedIp(url: string): Promise<string> {

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Prepend the scheme: use absolute URLs like "https://example.com/path"
  2. Trim and validate the URL string before calling - encode/escape any user-supplied segments
  3. Store normalized URLs at write time (e.g. new URL(input).toString()) so bad values never reach the fetch
  4. Add upstream form validation requiring a full absolute URL

Example fix

// before
await outboundFetch("example.com/api") // Invalid URL.
// after
await outboundFetch("https://example.com/api")
Defensive patterns

Strategy: validation

Validate before calling

// validate the URL before fetching
function isParsableUrl(u: string): boolean {
  try {
    const parsed = new URL(u)
    return parsed.protocol === "http:" || parsed.protocol === "https:"
  } catch {
    return false
  }
}
if (!isParsableUrl(url)) throw new Error("Provide an absolute http(s) URL")

Type guard

function isAbsoluteHttpUrl(u: string): u is string {
  try {
    return new URL(u).protocol.startsWith("http")
  } catch {
    return false
  }
}

Try / catch

try {
  const res = await outboundFetch(url)
} catch (e: any) {
  if (e?.message === "Invalid URL.") {
    // normalize: trim, prepend https:// if scheme missing, then retry once
  } else throw e
}

Prevention

When it happens

Trigger: Calling outboundFetch functions (fetch/get etc.) with a URL like "example.com/api" (missing scheme), an empty string, whitespace, or other input that `new URL()` cannot parse.

Common situations: User-supplied webhook/query URLs stored without a scheme; template-interpolated URLs producing "https://undefined/..."-adjacent garbage; config values missing "https://" prefix; trailing spaces from form input.

Related errors


AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29). Data as JSON: /api/errors/0ee75f7be8953122. Report an issue: GitHub.