ruvnet/ruflo · error · HttpFetchValidationError
INVALID_URL
INVALID_URL
Error message
invalid URL: ${rawUrl} What it means
Thrown by validateUrl in the http_fetch MCP tool when the native URL constructor cannot parse the input string. This is the first validation gate of the secure-by-default fetch pipeline (ADR-164 §5.1.8); it rejects malformed URLs before any protocol or host checks run. The error carries code INVALID_URL.
Source
Thrown at v3/@claude-flow/cli/src/mcp-tools/http-fetch-tools.ts:51
export class HttpFetchValidationError extends Error {
constructor(message: string, public readonly code: string) {
super(message);
this.name = 'HttpFetchValidationError';
}
}
/**
* Decide whether the URL is permitted under the default secure-by-default
* allowlist. Block file://, ftp://, RFC-1918 private addresses, loopback,
* link-local — unless CLAUDE_FLOW_HTTP_FETCH_ALLOW_PRIVATE=1 is set.
*/
export function validateUrl(rawUrl: string): URL {
let parsed: URL;
try {
parsed = new URL(rawUrl);
} catch {
throw new HttpFetchValidationError(`invalid URL: ${rawUrl}`, 'INVALID_URL');
}
const proto = parsed.protocol.toLowerCase();
if (proto !== 'http:' && proto !== 'https:') {
throw new HttpFetchValidationError(
`protocol ${parsed.protocol} not allowed (only http: and https:)`,
'FORBIDDEN_PROTOCOL',
);
}
const host = parsed.hostname.toLowerCase();
const allowPrivate = process.env.CLAUDE_FLOW_HTTP_FETCH_ALLOW_PRIVATE === '1';
if (!allowPrivate && isPrivateOrLoopback(host)) {
throw new HttpFetchValidationError(
`host ${host} is loopback/private/link-local; set CLAUDE_FLOW_HTTP_FETCH_ALLOW_PRIVATE=1 to override`,
'PRIVATE_ADDRESS',
);
}
return parsed;
}View on GitHub (pinned to 6b01dc5a68)
Solutions
- Provide an absolute URL with an explicit scheme: 'https://example.com/path'.
- URL-encode query parameters with encodeURIComponent before concatenating.
- Trim whitespace and surrounding angle brackets from pasted URLs.
- Pre-validate with `new URL(url)` in a try/catch before calling http_fetch.
Example fix
// before
http_fetch({ url: 'example.com/api?q=a b' })
// after
http_fetch({ url: 'https://example.com/api?q=' + encodeURIComponent('a b') }) Defensive patterns
Strategy: validation
Validate before calling
function safeParseUrl(raw) {
try { return new URL(raw); }
catch { throw new Error(`invalid URL: ${raw}`); }
} Type guard
function isValidUrl(s: unknown): s is string {
if (typeof s !== 'string') return false;
try { new URL(s); return true; } catch { return false; }
} Prevention
- Always include the scheme (https://).
- encodeURI/encodeURIComponent query parameters.
- Trim pasted URLs of surrounding whitespace/brackets.
When it happens
Trigger: Passing a URL string that fails `new URL(rawUrl)` — empty string, missing scheme ('example.com'), unencoded spaces, stray characters, or a non-string value coerced to string. The check runs inside the validateUrl helper which the http_fetch handler calls.
Common situations: Omitting the https:// scheme; pasting a URL with spaces or angle brackets; building a URL from unencoded user input with query parameters; passing a relative path instead of an absolute URL.
Related errors
- candidate ${label} must ingest at least one vector
- records must be a non-empty array of {id?, vector, text?}
- Key exceeds maximum nesting depth of ${MAX_NESTING_DEPTH}
- FORBIDDEN_PROTOCOL
- INVALID_HEADER_VALUE
AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12).
Data as JSON: /api/errors/7aba912ba532475b.
Report an issue: GitHub.