can1357/oh-my-pi · error · Error
Destination option ${optionName} must use http or https
Error message
Destination option ${optionName} must use http or https What it means
Thrown by httpBase() when a destination option expected to be a base URL parses as a valid absolute URL but its protocol is neither http: nor https:. The blob-broker requires every self-hosted destination base/public URL to point at an HTTP(S) endpoint so uploads and generated public links are well-formed. Non-HTTP schemes (ftp:, sftp:, file:, ws:) are rejected at uploader creation time.
Source
Thrown at packages/coding-agent/src/blob-broker/uploaders-self-hosted.ts:137
}
function endpoint(base: string, ...parts: string[]): string {
const url = new URL(base);
url.pathname = `${url.pathname.replace(/\/+$/, "")}/${encodedPath(parts)}`;
url.search = "";
url.hash = "";
return url.toString();
}
function httpBase(value: string, optionName: string): URL {
let url: URL;
try {
url = new URL(value);
} catch {
throw new Error(`Destination option ${optionName} must be an absolute HTTP URL`);
}
if (url.protocol !== "http:" && url.protocol !== "https:") {
throw new Error(`Destination option ${optionName} must use http or https`);
}
return url;
}
function publicUrl(baseValue: string, directory: string | undefined, filename: string): string {
const url = httpBase(baseValue, "publicBaseUrl");
const relative = encodedPath([...pathParts(directory), filename]);
url.pathname = `${url.pathname.replace(/\/+$/, "")}/${relative}`;
url.hash = "";
return url.toString();
}
function basicAuthorization(username: string, password: string): string {
return `Basic ${Buffer.from(`${username}:${password}`, "utf8").toString("base64")}`;
}
function expiry(days: number | undefined): { expiresAt?: number; expireDate?: string } {
if (days === undefined || days <= 0) return {};View on GitHub (pinned to 9690622007)
Solutions
- Set the option to an absolute URL starting with http:// or https://, e.g. https://files.example.com/share.
- If the underlying transfer really is FTP, keep the ftp:// URL only in options.host/transfer settings and give publicBaseUrl an https:// web address.
- Verify the option name you set matches what the destination expects (publicBaseUrl vs host vs apiUrl) — you may have put the URL in the wrong key.
- Recreate or reload the destination after fixing the config; the check runs once at uploader creation (createSelfHostedUploader).
Example fix
// before
{ "destination": "shared-folder", "options": { "root": "/srv/share", "publicBaseUrl": "file:///srv/share" } }
// after
{ "destination": "shared-folder", "options": { "root": "/srv/share", "publicBaseUrl": "https://files.example.com/share" } } Defensive patterns
Strategy: validation
Validate before calling
function isHttpBase(value) {
try { const u = new URL(value); return u.protocol === 'http:' || u.protocol === 'https:'; }
catch { return false; }
}
if (!isHttpBase(config.publicBaseUrl)) throw new Error('publicBaseUrl must be an http(s) URL'); Try / catch
try {
await uploader.upload(request);
} catch (err) {
if (err instanceof Error && /must use http or https/.test(err.message)) {
// surface a config-validation failure to the operator before retrying
} else throw err;
} Prevention
- Validate every base-URL option with new URL() plus a protocol allowlist at config load time.
- Keep transfer-protocol URLs (ftp://) separate from public web URLs (https://) in your schema.
- Add a config schema check that rejects non-http(s) schemes for *BaseUrl/host/endpoint keys.
- Normalize options early: strip trailing slashes and require absolute URLs.
When it happens
Trigger: Passing options.publicBaseUrl (ftp/shared-folder), options.host (owncloud), or options.endpoint/apiUrl (plik/seafile) with a scheme other than http or https, e.g. "ftp://mirror.example.com", "localhost:8080" normalized oddly, or a bare "file:///srv/share".
Common situations: Copy-pasting an FTP/SFTP host into publicBaseUrl when configuring the ftp destination; using a ws:// or file:// URL; forgetting that publicBaseUrl must be where end users browse, not the transfer protocol; typos like http// (which fails earlier at 850's sibling 'absolute HTTP URL' throw).
Related errors
- the discovery endpoint returned incomplete upload-node metad
- resultBaseUrl is not a valid URL
- the upload node did not return a direct image URL
- ${reason}
- no built-in uploader or serving adapter is implemented
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/5712bc5a86fc030d.
Report an issue: GitHub.