agalwood/Motrix · error · AppError
PLUGIN_MANIFEST_INVALID
PLUGIN_MANIFEST_INVALID
Error message
plugin.install.registry_url_not_allowlisted
What it means
Thrown by assertAllowlistedPackageUrl when `new URL(rawUrl)` throws — i.e. entry.package.url is not a parseable URL string. Categorized as PLUGIN_MANIFEST_INVALID because the package URL is part of the registry DTO that describes an installable plugin. This is the first of two guards in the same function (the second, error 209, checks scheme/host).
Source
Thrown at src/core/plugin/registry/registry-fetcher.ts:22
// in memory BEFORE anything is written to disk.
import { createHash } from 'node:crypto'
import { mkdir, writeFile } from 'node:fs/promises'
import path from 'node:path'
import { AppError, ErrorCode } from '@shared/errors'
import type { RegistryPluginDTO } from '@shared/schemas/registry'
export const REGISTRY_PACKAGE_HOSTS: ReadonlySet<string> = new Set([
'github.com',
'dl.motrix.app',
])
export function assertAllowlistedPackageUrl(rawUrl: string): URL {
let u: URL
try {
u = new URL(rawUrl)
} catch {
throw new AppError(
ErrorCode.PluginManifestInvalid,
'plugin.install.registry_url_not_allowlisted'
)
}
if (u.protocol !== 'https:' || !REGISTRY_PACKAGE_HOSTS.has(u.hostname)) {
throw new AppError(
ErrorCode.PluginManifestInvalid,
'plugin.install.registry_url_not_allowlisted'
)
}
return u
}
export async function fetchVerifiedPackageBytes(
entry: RegistryPluginDTO,
fetchImpl: typeof fetch = fetch
): Promise<Buffer> {
const pkg = entry.packageView on GitHub (pinned to 1a708ee577)
Solutions
- Inspect entry.package.url — it must be a fully-qualified URL string including scheme.
- Correct the registry source so the URL is valid before install/update runs.
- If consuming untrusted registry JSON, validate entry.package.url with `new URL(...)` in a try/catch before calling fetchVerifiedPackageBytes.
Example fix
// before — registry entry
{ "package": { "url": "github.com/foo/bar/v1.moext", "size": 1, "sha256": "..." } }
// after
{ "package": { "url": "https://github.com/foo/bar/releases/download/v1/bundle.moext", "size": 12345, "sha256": "<64 hex>" } } Defensive patterns
Strategy: validation
Validate before calling
import { assertAllowlistedPackageUrl } from '@core/plugin/registry/registry-fetcher'
function isValidPackageUrl(rawUrl: string): boolean {
try { new URL(rawUrl); return true } catch { return false }
}
if (!isValidPackageUrl(entry.package?.url ?? '')) {
throw new Error('package.url is not a valid URL — fix the registry entry before install')
} Type guard
function isParsableUrl(s: unknown): s is string {
if (typeof s !== 'string') return false
try { new URL(s); return true } catch { return false }
} Try / catch
try {
await fetchVerifiedPackageBytes(entry)
} catch (e) {
if (e instanceof AppError && e.code === ErrorCode.PluginManifestInvalid && e.message === 'plugin.install.registry_url_not_allowlisted' && !isParsableUrl(entry.package?.url)) {
reportMalformedRegistryUrl(entry)
} else throw e
} Prevention
- Validate package.url with `new URL(...)` before attempting install/update.
- Generate registry entries with a publisher tool that always emits fully-qualified https URLs.
- Reject registry files whose package.url is missing or relative at schema-load time.
When it happens
Trigger: fetchVerifiedPackageBytes(entry) or downloadRegistryMoext(entry) is called and entry.package.url is malformed (empty, relative, missing protocol, embedded spaces, or not a string the URL constructor accepts).
Common situations: Registry JSON was hand-edited and the package URL was truncated. A registry entry template left a placeholder like "<url>". Proxy rewrote/encoded the URL badly. Schema validation upstream was bypassed.
Related errors
- PLUGIN_MANIFEST_INVALID
- PLUGIN_MANIFEST_INVALID
- invalid-url-scheme
- invalid Chrome extension ID: ${id}
- invalid Firefox extension ID: ${id}
AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12).
Data as JSON: /api/errors/cd810066ee8f5861.
Report an issue: GitHub.