agalwood/Motrix · error · BridgeReceiverError
invalid-url-scheme
invalid-url-scheme
Error message
URL must be http: or https:
What it means
Thrown by SubmitDownloadAdapter.adapt when a direct, hls, or dash selection provides a primary URL that does not begin with http:// or https:// (case-insensitive regex). MDXP's Resource.url is typed as plain z.string() (not URL-validated), so this is a business-rule guard that runs after schema parsing. Code 'invalid-url-scheme' is a wire-contract code the extension can branch on.
Source
Thrown at src/core/bridge-receiver/submit-download-adapter.ts:100
async adapt(
params: DownloadSubmitParams,
input: AdaptInput
): Promise<
AdaptedDirect | AdaptedMagnet | AdaptedHls | AdaptedDash | AdaptedMux
> {
// Bootstrap already ran DownloadSubmitParamsSchema.safeParse() and threw
// InvalidParams on failure. We have typed data here, but MDXP's
// Resource.url is plain z.string() (not http-only), so we still need to
// reject non-http(s) schemes as a business rule.
if (
params.selection.kind === 'direct' ||
params.selection.kind === 'hls' ||
params.selection.kind === 'dash'
) {
const url = params.selection.primary.url
if (!/^https?:\/\//i.test(url)) {
throw new BridgeReceiverError(
'invalid-url-scheme',
'URL must be http: or https:'
)
}
}
if (params.selection.kind === 'mux') {
for (const r of [params.selection.video, params.selection.audio]) {
if (!/^https?:\/\//i.test(r.url)) {
throw new BridgeReceiverError(
'invalid-url-scheme',
'URL must be http: or https:'
)
}
}
}
const { selection, source, meta } = params
View on GitHub (pinned to 1a708ee577)
Solutions
- Validate the URL scheme on the extension side before submitting — only submit http/https URLs for direct/hls/dash kinds
- If the resource is actually a magnet link, submit it with selection.kind 'magnet' instead
- Sanitize or reject blob:/data:/file: URLs at capture time in the extension
Example fix
// before
await adapter.adapt({ selection: { kind: 'direct', primary: { url: 'ftp://example.com/file.mp4', ... } }, ... }, input)
// after
await adapter.adapt({ selection: { kind: 'direct', primary: { url: 'https://example.com/file.mp4', ... } }, ... }, input) Defensive patterns
Strategy: validation
Validate before calling
function isValidHttpUrl(url: string): boolean {
return /^https?:\/\//i.test(url)
}
// Before calling adapt:
if (!isValidHttpUrl(params.selection.primary.url)) {
throw new Error(`Refusing to submit non-http URL: ${params.selection.primary.url}`)
} Type guard
function isHttpUrl(url: string): url is \`http\${string}\` | \`https\${string}\` {
return /^https?:\/\//i.test(url)
} Try / catch
try {
await adapter.adapt(params, input)
} catch (e) {
if (e instanceof BridgeReceiverError && e.code === 'invalid-url-scheme') {
showError('Only http:// and https:// URLs are supported for this download type')
} else throw e
} Prevention
- Validate URL scheme in the extension before submitting — filter out blob:, data:, file:, ftp: at capture time
- Use magnet selection kind for magnet URIs instead of direct
When it happens
Trigger: params.selection.kind is 'direct', 'hls', or 'dash' and params.selection.primary.url fails the regex /^https?:\/\//i — e.g. it starts with 'ftp://', 'file://', 'magnet:', 'data:', 'javascript:', or is a relative path.
Common situations: Extension captures a non-http media link (ftp download, blob URL); a malformed or truncated URL is passed; a magnet URI is incorrectly classified as 'direct'; a data: URI for an inline media element is captured.
Related errors
- plugin.http.invalid_url
- PLUGIN_MANIFEST_INVALID
- unsupported-kind
- 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/f0c6052a0d1b2349.
Report an issue: GitHub.