paperclipai/paperclip · error
PAPERCLIP_CHAT_WEBHOOK_PUBLIC_URL must be an HTTPS origin…
Error message
PAPERCLIP_CHAT_WEBHOOK_PUBLIC_URL must be an HTTPS origin without credentials, a path, query, or fragment
What it means
parseChatWebhookPublicBaseUrl validates the PAPERCLIP_CHAT_WEBHOOK_PUBLIC_URL environment variable. It requires an HTTPS origin with no credentials, path, query, or fragment because the value is used as a public webhook base origin. If URL parsing fails or any constraint is violated, it throws this error and deliberately omits the offending URL from the message so credentials never leak into logs.
Solutions
- Set PAPERCLIP_CHAT_WEBHOOK_PUBLIC_URL to a bare HTTPS origin only, e.g. https://abc123.ngrok.io (no path, query, credentials, or fragment)
- If you need a path, configure it in the webhook route settings instead of the base URL env var
- Check for trailing slashes, quotes, or whitespace copied into the env value
- Ensure your tunnel/proxy terminates TLS so the public URL is genuinely HTTPS
Example fix
// before PAPERCLIP_CHAT_WEBHOOK_PUBLIC_URL=https://tunnel.example.com/webhook?key=abc // after PAPERCLIP_CHAT_WEBHOOK_PUBLIC_URL=https://tunnel.example.com
Defensive patterns
Strategy: validation
Validate before calling
const raw = process.env.PAPERCLIP_CHAT_WEBHOOK_PUBLIC_URL;
function isValidPublicOrigin(u?: string): boolean {
if (!u) return false;
try { const url = new URL(u);
return url.protocol === "https:" && !url.username && !url.password
&& url.pathname === "/" && !url.search && !url.hash;
} catch { return false; }
}
if (!isValidPublicOrigin(raw)) throw new Error("PAPERCLIP_CHAT_WEBHOOK_PUBLIC_URL must be a bare HTTPS origin"); Type guard
function isValidWebhookPublicUrl(v: unknown): v is string {
if (typeof v !== "string") return false;
try { const u = new URL(v);
return u.protocol === "https:" && !u.username && !u.password && u.pathname === "/" && !u.search && !u.hash;
} catch { return false; }
} Prevention
- Never append a path, query, or credentials to the webhook public URL env var
- Validate the env var with a startup config check before deploying
- Prefer tunnel providers that give stable HTTPS origins (ngrok, Cloudflare Tunnel)
- Strip trailing slashes and surrounding quotes when copying the URL into config
When it happens
Trigger: Setting PAPERCLIP_CHAT_WEBHOOK_PUBLIC_URL to an http:// URL, a URL with embedded user:pass credentials, a URL containing a path (/webhook), query (?x=1), or fragment (#frag), or any value that fails `new URL()` parsing; invoked by loadConfig and webhookPublicBaseUrl at startup.
Common situations: Operators pasting a full tunnel/ngrok forwarding URL like https://xyz.ngrok.io/webhook instead of just the origin; using http:// for a local dev tunnel; typos or whitespace in the env var making the URL unparseable.
Understand the failure class
Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.
Related errors
- RUNNER_PROTOCOL_EVAL_HISTORY_PUBLIC_BASE_URL must be a…
- CreateOS API URL is invalid.
- CreateOS API URL must be an HTTPS origin (optionally ending…
- Invalid PAPERCLIP_PAGE_DEFAULT_PREFIX: use lowercase path…
- Invalid public base URL
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/f00bb96d671b9cdc.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/chat-webhook-public-url.ts:21
value: string | null | undefined,
): string | undefined {
if (!value?.trim()) return undefined;
try {
const url = new URL(value.trim());
if (
url.protocol === "https:" &&
url.hostname &&
!url.username &&
!url.password &&
url.pathname === "/" &&
!url.search &&
!url.hash
)
return url.origin;
} catch {
// Never include an operator-supplied URL: it could contain credentials.
}
throw new Error(
"PAPERCLIP_CHAT_WEBHOOK_PUBLIC_URL must be an HTTPS origin without credentials, a path, query, or fragment",
);
}
View on GitHub (pinned to 3f1d897a7c)