paperclipai/paperclip · error
reuseLease must be a boolean.
Error message
reuseLease must be a boolean.
What it means
parseConfig validates the optional reuseLease option: if present it must be a boolean. The plugin converts it to a strict true/false (raw.reuseLease === true), so truthy non-boolean values like "true" or 1 are rejected rather than coerced.
Solutions
- Change reuseLease to a real boolean: true or false (unquoted).
- Remove the key entirely when the default (false) is acceptable — only non-null non-booleans are rejected.
- If the config comes from env vars, parse it first, e.g. reuseLease: process.env.REUSE_LEASE === 'true'.
Example fix
// before
{ "reuseLease": "true" }
// after
{ "reuseLease": true } Defensive patterns
Strategy: validation
Validate before calling
if (cfg.reuseLease != null && typeof cfg.reuseLease !== 'boolean') throw new Error('reuseLease must be a boolean'); Prevention
- Use real JSON booleans, not "true"/"false" strings
- Parse string env-driven flags with === 'true'
- Omit the key entirely to accept the default
When it happens
Trigger: Setting reuseLease to a string ("true"/"false"), a number (0/1), null-as-string, or an object in the CreateOS environment config and calling parseConfig via client/config construction or the validate/probe hooks.
Common situations: Editing a JSON/YAML config by hand and leaving the value quoted; environment-variable-driven configs where everything arrives as a string; copying a JS config where the value was a 0/1 flag.
Related errors
- must be a non-empty string.
- 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
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/492c3dc3cff29f21.
Report an issue: GitHub.
Appendix: source
Thrown at packages/plugins/sandbox-providers/createos/src/config.ts:39
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 {
apiUrl: url.origin,
apiKey: text("apiKey"),
shape,
rootfs: text("rootfs"),
region: text("region"),
timeoutMs,
reuseLease: raw.reuseLease === true,
};
}
export function resolveApiKey(config: CreateosConfig): string {
if (!config.apiKey && config.apiUrl !== "https://api.sb.createos.sh") {
throw new Error("Custom CreateOS API endpoints require an explicit environment API key; the host fallback is only available for https://api.sb.createos.sh.");
}
const key = config.apiKey ?? process.env.CREATEOS_API_KEY?.trim();
if (!key || /[\r\n\0]/.test(key)) {View on GitHub (pinned to 3f1d897a7c)