nexu-io/open-design · warning
Enter a valid http(s) website URL.
Error message
Enter a valid http(s) website URL.
What it means
Thrown by startBrandExtraction when the user supplied a url but normalizeUrl(rawUrl) returned null. normalizeUrl prepends https:// when no scheme is present, parses with new URL, and only accepts http/https protocols. The route handler maps this message to HTTP 400 (bad request).
Source
Thrown at apps/daemon/src/brands/index.ts:289
try {
return new URL(url).hostname.replace(/^www\./i, '');
} catch {
return url;
}
}
/**
* Reserve a brand and stand up the agent-driven extraction project. Throws on
* an invalid URL (the route maps that to a 400). The caller navigates into the
* returned project and auto-sends the seeded prompt to start the agent.
*/
export async function startBrandExtraction(
opts: StartBrandExtractionOptions,
): Promise<StartBrandExtractionResult> {
const designMd = normalizeDesignMdInput(opts.designMd);
const rawUrl = (opts.url ?? '').trim();
const url = rawUrl ? normalizeUrl(rawUrl) : designMd ? sourceUrlForDesignMd(designMd, opts.description) : null;
if (rawUrl && !url) throw new Error('Enter a valid http(s) website URL.');
if (!url) throw new Error('Enter a valid http(s) website URL or paste a DESIGN.md.');
const hasWebsiteSource = /^https?:\/\//i.test(url);
const hasDesignMdSource = Boolean(designMd);
const {
brandsRoot,
projectsRoot,
skillsRoot,
db,
randomId = randomUUID,
logoFallback = ensureLogoFallback,
seedFallback = ensureBrandSeed,
imageryFallback = ensureImageryFallback,
} = opts;
const id = newBrandId(url);
const projectId = brandProjectId(id);
const conversationId = randomId();
const host = hostnameOf(url);View on GitHub (pinned to 5be4028344)
Solutions
- Trim whitespace and ensure the URL has an http or https scheme (or no scheme, which normalizeUrl will prefix).
- Reject non-http(s) schemes early on the client.
- Validate with new URL(value) and check protocol is http: or https: before submitting.
Example fix
// before
await startBrandExtraction({ url: 'ftp://example.com', /* deps */ }); // throws
// after
await startBrandExtraction({ url: 'https://example.com', /* deps */ }); Defensive patterns
Strategy: validation
Validate before calling
function normalizeUrl(raw: string): string | null {
const trimmed = (raw ?? '').trim();
if (!trimmed) return null;
const withScheme = /^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed) ? trimmed : `https://${trimmed}`;
let parsed: URL;
try { parsed = new URL(withScheme); } catch { return null; }
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') return null;
return parsed.href;
}
const normalized = normalizeUrl(userInput);
if (userInput.trim() && !normalized) {
throw new Error('Enter a valid http(s) website URL.');
} Type guard
function isHttpUrl(raw: string): boolean {
try {
const u = new URL(/^https?:\/\//i.test(raw) ? raw : `https://${raw}`);
return u.protocol === 'http:' || u.protocol === 'https:';
} catch {
return false;
}
} Try / catch
try {
await startBrandExtraction({ url: userInput, /* deps */ });
} catch (err) {
if (err instanceof Error && err.message === 'Enter a valid http(s) website URL.') {
return badRequest('Please enter a valid http or https URL.');
}
throw err;
} Prevention
- Trim user input and auto-prepend https:// on the client before submit.
- Reject non-http(s) schemes (ftp, file, mailto) early.
- Validate with new URL(value) on the client so malformed input never reaches the daemon.
When it happens
Trigger: The URL is malformed ('htp://example', 'example..com'), uses an unsupported scheme ('ftp://', 'file://', 'mailto:'), contains characters that make new URL throw, or is structurally unparseable.
Common situations: User pastes with a typo in the scheme, trailing whitespace, missing dot, or surrounding quotes; CSV/bulk import containing malformed rows; client not trimming input.
Related errors
- brand.json is not valid JSON.
- brand.json failed validation: ${errorMessage(err)}
- invalid brand id: ${input.brandId}
- invalid design system id: ${designSystemId}
- invalid JSON in ${filePath}: ${message}
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/f9e9b84991fe88d3.
Report an issue: GitHub.