paperclipai/paperclip · error
CreateOS API URL is invalid.
Error message
CreateOS API URL is invalid.
What it means
After confirming apiUrl is present, parseConfig parses it with new URL() and rejects strings that are not absolute, well-formed URLs. This error means the configured apiUrl could not be parsed as a URL at all — it is not a syntax/protocol-policy rejection, which produces different messages.
Solutions
- Change apiUrl to a full absolute URL including scheme, e.g. https://createos.example.com (http allowed only for localhost/127.0.0.1/[::1]).
- Trim surrounding whitespace and remove stray quotes from the configured value.
- Validate in the browser/node with `new URL(value)` before saving the config to fail fast with a friendly message.
- If a path prefix is needed, keep it to "", "/", "/v1", or "/v1/" — other paths also fail validation.
Example fix
// before
parseConfig({ apiUrl: "createos.internal", apiKey });
// after
parseConfig({ apiUrl: "https://createos.internal", apiKey }); Defensive patterns
Strategy: validation
Validate before calling
function prevalidateUrl(value) {
let url;
try { url = new URL(String(value).trim()); } catch { throw new Error(`apiUrl '${value}' is not a valid absolute URL; include the scheme (https://...)`); }
if (!url.protocol.startsWith("http")) throw new Error("apiUrl must use http(s)");
return url;
} Try / catch
try {
config = parseConfig(raw);
} catch (err) {
if (err.message === "CreateOS API URL is invalid.")
throw new Error(`apiUrl '${raw.apiUrl}' is not a valid URL. Use a full absolute URL like https://createos.example.com (path must be '', '/', '/v1', or '/v1/').`);
throw err;
} Prevention
- Always include the scheme (https://) when entering apiUrl.
- Trim whitespace and remove wrapping quotes from pasted URLs.
- Validate with new URL() in the config UI before saving.
- Keep the URL path to '', '/', '/v1', or '/v1/'; use http only for localhost/127.0.0.1/[::1].
When it happens
Trigger: Configuring apiUrl as "createos.example.com" (missing scheme), "https://" (empty host), a value with spaces or invalid characters, or a relative path like "/api".
Common situations: Users omitting the https:// prefix when filling in the board config form, copy-paste introducing whitespace/quotes, or env files where the value got mangled (e.g. unescaped # truncating the URL).
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
- ACPX profile requires exact model ; received
- ACPX model must not be empty
- ACPX provider identity contains an invalid permission mode
- ACPX provider identity contains invalid lifetime fences
- AWS AgentCore evals require exact model…
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/e10b1002cf0c4644.
Report an issue: GitHub.
Appendix: source
Thrown at packages/plugins/sandbox-providers/createos/src/config.ts:23
rootfs: string | null;
region: string | null;
timeoutMs: number;
reuseLease: boolean;
}
export function parseConfig(raw: Record<string, unknown>): CreateosConfig {
const text = (key: string): string | null => {
const value = raw[key];
if (value == null) return null;
if (typeof value !== "string" || !value.trim() || value.includes("\0")) {
throw new Error(`${key} must be a non-empty string.`);
}
return value.trim();
};
const apiUrl = text("apiUrl");
if (!apiUrl) throw new Error("CreateOS requires an API URL.");
let url: URL;
try { url = new URL(apiUrl); } catch { throw new Error("CreateOS API URL is invalid."); }
// Configuration is board-owned, but never follow redirects with the API key.
// Plain HTTP is useful for a loopback development server only.
const loopback = ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname);
if ((url.protocol !== "https:" && !(url.protocol === "http:" && loopback)) ||
url.username || url.password || url.search || url.hash ||
!["", "/", "/v1", "/v1/"].includes(url.pathname)) {
throw new Error("CreateOS API URL must be an HTTPS origin (optionally ending in /v1); HTTP is allowed on loopback only.");
}
const shape = text("shape");
if (!shape) throw new Error("CreateOS requires a shape from its shape catalog.");
const timeoutMs = raw.timeoutMs ?? 300_000;
if (typeof timeoutMs !== "number" || !Number.isInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 86_400_000) {
throw new Error("timeoutMs must be an integer between 1 and 86400000.");
}
if (raw.reuseLease != null && typeof raw.reuseLease !== "boolean") {
throw new Error("reuseLease must be a boolean.");
}
return {View on GitHub (pinned to 3f1d897a7c)