decolua/9router · error
Invalid URL format
Error message
Invalid URL format
What it means
After confirming a `url` string was provided, handleFetch validates it with the WHATWG URL parser (new URL(targetUrl)). A SyntaxError - meaning the string is not an absolute URL with a scheme like http:// or https:// - produces HTTP 400 'Invalid URL format'. Relative paths, bare hostnames, and malformed URLs are all rejected here.
Source
Thrown at src/sse/handlers/fetch.js:78
return errorResponse(HTTP_STATUS.UNAUTHORIZED, "Invalid API key");
}
}
if (!providerInput || typeof providerInput !== "string") {
log.warn("FETCH", "Missing provider/model");
return errorResponse(HTTP_STATUS.BAD_REQUEST, "Missing required field: provider (or model)");
}
if (!targetUrl || typeof targetUrl !== "string") {
log.warn("FETCH", "Missing url");
return errorResponse(HTTP_STATUS.BAD_REQUEST, "Missing required field: url");
}
// Validate URL format
try {
new URL(targetUrl);
} catch {
log.warn("FETCH", "Invalid URL", { url: targetUrl });
return errorResponse(HTTP_STATUS.BAD_REQUEST, "Invalid URL format");
}
// SSRF guard: reject internal/private/metadata targets
try {
assertPublicUrl(targetUrl);
} catch (err) {
log.warn("FETCH", "Blocked URL", { url: targetUrl });
return errorResponse(HTTP_STATUS.BAD_REQUEST, err.message);
}
// Combo expansion: providerInput may be a combo name → run fallback/round-robin across providers
const combos = await getCombos();
const comboModels = getComboModelsFromData(providerInput, combos);
if (comboModels) {
const comboStrategies = settings.comboStrategies || {};
const comboStrategy = comboStrategies[providerInput]?.fallbackStrategy || settings.comboStrategy || "fallback";
const comboStickyLimit = settings.comboStickyRoundRobinLimit;View on GitHub (pinned to 90b52e06ff)
Solutions
- Prefix the scheme if missing: 'https://' + host when the input is a bare hostname
- Trim whitespace and strip wrapping quotes/angle brackets from the URL string before sending
- Pre-validate client-side with new URL(value) inside try/catch to catch it before the request
- URL-encode unsafe characters (spaces, unencoded non-ASCII) in query/path segments
Example fix
// before const url = 'example.com/docs'; // after const raw = 'example.com/docs'.trim(); const url = /^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(raw) ? raw : 'https://' + raw;
Defensive patterns
Strategy: validation
Validate before calling
function assertAbsoluteUrl(value) {
if (typeof value !== 'string') throw new TypeError('url must be a string');
const u = new URL(value); // throws SyntaxError on invalid input
if (!['http:', 'https:'].includes(u.protocol)) throw new TypeError('url must be http(s)');
return u.href;
}
const safeUrl = assertAbsoluteUrl(input.trim()); Type guard
function isParseableUrl(value) {
if (typeof value !== 'string') return false;
try { const u = new URL(value); return u.protocol === 'http:' || u.protocol === 'https:'; } catch { return false; }
} Try / catch
try {
const res = await fetch(endpoint, { method: 'POST', body: JSON.stringify({ model, url }) });
if (res.status === 400 && (await res.text()).includes('Invalid URL format')) {
console.error('Not an absolute URL:', url);
}
} catch (err) { /* network failure */ } Prevention
- Run new URL(value) in the client before sending; it fails on the same inputs the server rejects
- Trim and strip whitespace/quotes from user-provided URLs
- Auto-prefix https:// when the input has no scheme
When it happens
Trigger: Sending url='example.com/page' (no scheme), url='/relative/path', url='http://' or 'https://[bad' (malformed), or any string the URL constructor cannot parse as absolute.
Common situations: Passing a hostname without protocol because browsers auto-prefix http://; user-typed input pasted with typos or spaces; template interpolation producing 'https://{missing}'; URLs truncated by a length-limited form field.
Related errors
- Missing required field: url
- err.message (SSRF guard: blocked internal/private/metadata U
- Unknown provider: ${providerInput}
- Provider ${providerId} does not support web fetch
- Invalid HuggingFace model ID
AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30).
Data as JSON: /api/errors/f7228852f79eb877.
Report an issue: GitHub.