Budibase/budibase · error · Error

Invalid Github URL

Error message

Invalid Github URL

What it means

parseGithubUrl validates that a plugin source URL is a well-formed URL. If new URL(url) throws (malformed URL), the function throws "Invalid Github URL". A subsequent check rejects non-https/non-github hosts with a different message, so this error is purely about URL parse failure.

Source

Thrown at packages/server/src/api/controllers/plugin/github.ts:13

import { utils as coreUtils } from "@budibase/backend-core"
import {
  deleteFolderFileSystem,
  getPluginMetadata,
} from "../../../utilities/fileSystem"
import { downloadUnzipTarball } from "./utils"

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

  if (parsed.protocol !== "https:" || parsed.hostname !== "github.com") {
    throw new Error("The plugin origin must be from Github")
  }

  return parsed
}

export async function request(
  url: string,
  headers: Record<string, string> = {},
  err: string
) {
  const response = await coreUtils.fetchWithBlacklist(url, { headers })
  if (response.status >= 300) {
    const respErr = await response.text()
    throw new Error(`Error: ${err} - ${respErr}`)

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Prefix the URL with the scheme: https://github.com/<owner>/<repo>
  2. Use the HTTPS clone URL, not SSH (git@github.com:...)
  3. Trim whitespace and stray characters from the pasted URL
  4. Validate with new URL(url) in the browser console before submitting

Example fix

// before
await api.post("/api/plugins/github", { url: "github.com/user/repo" })
// after
await api.post("/api/plugins/github", { url: "https://github.com/user/repo" })
Defensive patterns

Strategy: validation

Validate before calling

const u = new URL(url)
if (u.protocol !== "https:" || u.hostname !== "github.com") {
  throw new Error(`URL must be https://github.com/... got ${url}`)
}
await api.post("/api/plugins/github", { url: u.toString() })

Type guard

const isGithubUrl = (url: string): boolean => {
  try { const u = new URL(url); return u.protocol === "https:" && u.hostname === "github.com" }
  catch { return false }
}

Try / catch

try {
  await api.post("/api/plugins/github", { url })
} catch (err) {
  if (err.message === "Invalid Github URL") {
    console.error(`Malformed URL "${url}" — use https://github.com/<owner>/<repo>`)
  } else { throw err }
}

Prevention

When it happens

Trigger: Calling the GitHub plugin upload endpoint with a URL that is not parseable — missing scheme ("github.com/user/repo"), spaces, typos, empty string, or a pasted SSH URL like git@github.com:user/repo.git.

Common situations: Pasting "github.com/budibase/plugins" without https:// into the builder's plugin import; copying SSH clone URLs instead of HTTPS; trailing garbage from copy/paste; relative paths submitted instead of absolute URLs.

Related errors


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