can1357/oh-my-pi · error
${destination} returned an invalid upload URL
Error message
${destination} returned an invalid upload URL What it means
httpUrl parses a URL string returned by (or configured for) a file host and throws when it cannot be parsed by the URL constructor. The library validates that upload URLs are well-formed before using them in requests, failing fast with a destination-specific message instead of an opaque fetch error later.
Source
Thrown at packages/coding-agent/src/blob-broker/uploaders-anonymous.ts:34
const UGUU_UPLOAD_URL = "https://uguu.se/upload?output=text";
const TMPFILES_UPLOAD_URL = "https://tmpfiles.org/api/v1/upload";
const HOUR_MS = 60 * 60 * 1_000;
const DAY_MS = 24 * HOUR_MS;
const LITTERBOX_TTLS = {
"1h": HOUR_MS,
"12h": 12 * HOUR_MS,
"24h": 24 * HOUR_MS,
"72h": 72 * HOUR_MS,
} as const;
function httpUrl(value: string, destination: BlobDestinationId): string {
const trimmed = value.trim();
let url: URL;
try {
url = new URL(trimmed);
} catch {
throw new Error(`${destination} returned an invalid upload URL`);
}
if (url.protocol !== "http:" && url.protocol !== "https:") {
throw new Error(`${destination} returned an unsupported upload URL`);
}
return url.href;
}
async function uploadTextUrl(
destination: BlobDestinationId,
config: DestinationRuntimeConfig,
endpoint: string,
form: FormData,
): Promise<{ response: Response; url: string }> {
const response = await expectOk(await fetchFor(config)(endpoint, { method: "POST", body: form }), destination);
return { response, url: httpUrl(await response.text(), destination) };
}
function remoteName(url: string): string | undefined {View on GitHub (pinned to 9690622007)
Solutions
- Include the scheme in configured URLs: `https://litterbox.catbox.moe/resources/internals/api.php`.
- Use absolute URLs for the base/uploadUrl options; relative paths are rejected.
- Trim whitespace/newlines from config values (the function trims but leading garbage before a scheme still fails).
- Verify the host is actually returning JSON with the expected URL field, not an error page.
Example fix
// before
{ "options": { "base": "litterbox.catbox.moe" } }
// after
{ "options": { "base": "https://litterbox.catbox.moe" } } Defensive patterns
Strategy: validation
Validate before calling
function isHttpUrl(v: unknown): boolean {
if (typeof v !== "string") return false;
try { const u = new URL(v.trim()); return u.protocol === "http:" || u.protocol === "https:"; } catch { return false; }
}
if (!isHttpUrl(config.options.base)) throw new Error("base must be an absolute http(s) URL"); Type guard
const parseHttpUrl = (v: string): URL | null => { try { const u = new URL(v.trim()); return u.protocol === "http:" || u.protocol === "https:" ? u : null; } catch { return null; } }; Try / catch
try {
uploader = createUploader(config);
} catch (err) {
if (String(err).includes("invalid upload URL")) {
logger.warn("check base/uploadUrl: must be absolute http(s) URL", { err: String(err) });
} else throw err;
} Prevention
- Always include the scheme (https://) in configured URLs.
- Validate config URLs at load time with new URL() and a protocol check.
- When a host returns the URL, verify the response is JSON with the expected field before treating it as a URL.
When it happens
Trigger: Calling httpUrl — via uploadTextUrl, absolutePomfUrl, uploadUrl, base, or response handling — when the value is not a parseable absolute URL: empty string, relative path like "/upload", text/html error page body accidentally used as URL, or a URL with spaces/control characters.
Common situations: Misconfigured base option ("example.com" without scheme), a host returning an HTML error page where JSON was expected and a field got used as the URL, or a proxy rewriting responses so the URL field is empty.
Related errors
- collab.webUrl must not include a query string or fragment
- Failed to load tree-sitter language: {err}
- Provider delete URL must not embed an account credential
- Destination option ${key} must be a string
- Destination option ${key} must be a finite number
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/a24638f56689e6db.
Report an issue: GitHub.