can1357/oh-my-pi · error
Invalid URL: ${input}
Error message
Invalid URL: ${input} What it means
parseInternalUrl first attempts standard URL parsing; on failure it falls back to regex extraction. If neither the URL constructor nor the regex can find a host/scheme structure, the input is not a parseable internal URL and this error is thrown with the raw input echoed.
Source
Thrown at packages/coding-agent/src/internal-urls/parse.ts:63
}
/**
* Parse an internal URL into an InternalUrl.
*
* Handles URLs where `new URL()` would fail (e.g., `skill://plugin:name`
* where the colon is not a port separator).
*/
export function parseInternalUrl(input: string): InternalUrl {
const hostMatch = input.match(SCHEME_HOST_RE);
const pathMatch = input.match(PATHNAME_RE);
let parsed: URL;
try {
parsed = new URL(input);
} catch {
// URL parse failed — build a minimal URL-like object from regex matches.
if (!hostMatch) {
throw new Error(`Invalid URL: ${input}`);
}
// Extract search and hash from the raw input before constructing the object.
const hashIdx = input.indexOf("#");
const hash = hashIdx !== -1 ? input.slice(hashIdx) : "";
const withoutHash = hashIdx !== -1 ? input.slice(0, hashIdx) : input;
const queryIdx = withoutHash.indexOf("?");
const search = queryIdx !== -1 ? withoutHash.slice(queryIdx) : "";
const queryString = search.slice(1); // strip leading ?
// Strip search/hash from pathname captured by regex.
let rawPathname = pathMatch?.[1] ?? "";
if (queryIdx !== -1 && rawPathname.includes("?")) {
rawPathname = rawPathname.slice(0, rawPathname.indexOf("?"));
}
parsed = {
protocol: `${hostMatch[1]}:`,
hostname: hostMatch[2] ?? "",View on GitHub (pinned to 9690622007)
Solutions
- Ensure the input includes a supported scheme prefix, e.g. 'omp://docs' or 'memory://summary.md'.
- Trim whitespace and verify the value is a URL, not a filesystem path; use file:// for paths.
- Validate with a quick regex like /^[a-z][a-z0-9+.-]*:\/\//i before calling.
Example fix
// before
parseInternalUrl(userText);
// after
if (!/^[a-z][a-z0-9+.-]*:\/\//i.test(userText.trim())) throw new Error('expected scheme:// URL');
parseInternalUrl(userText.trim()); Defensive patterns
Strategy: validation
Validate before calling
const URL_LIKE = /^[a-z][a-z0-9+.-]*:\/\/\S+/i;
if (!URL_LIKE.test(input.trim())) throw new Error(`not an internal URL: ${input}`); Type guard
const looksLikeUrl = (s: string): boolean => /^[a-z][a-z0-9+.-]*:\/\//i.test(s.trim());
Try / catch
try {
return parseInternalUrl(input);
} catch (err) {
if (err instanceof Error && err.message.startsWith('Invalid URL:')) throw new Error(`expected scheme:// URL, got: ${input}`);
throw err;
} Prevention
- Validate input matches scheme://host shape before calling the parser.
- Trim whitespace and reject empty strings early.
- Distinguish file paths from URLs at the API boundary; wrap paths in file:// explicitly.
When it happens
Trigger: Calling parseInternalUrl (directly or via router.resolve/write) with a string lacking a recognizable scheme://host structure — e.g. a bare filename, empty string, whitespace, or garbage text.
Common situations: Passing a plain file path where a URL is expected; trimming/whitespace mistakes; tool output accidentally fed back as a URL.
Related errors
- err.to_string() (timestamp parse error)
- duration is too large: {value}
- invalid date: {value}
- date is out of range
- dates before 1970 are unsupported
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/f66356c0f3ed18b3.
Report an issue: GitHub.