paperclipai/paperclip · error

timeoutMs must be an integer between 1 and 86400000.

Error message

timeoutMs must be an integer between 1 and 86400000.

What it means

parseConfig validates the optional timeoutMs as an integer between 1 and 86,400,000 (1 ms to 24 hours). Non-integer numbers, zero, negative values, and values above 24h are rejected. If omitted, a default of 300,000 ms (5 minutes) applies.

Solutions

  1. Set timeoutMs to an integer number of milliseconds between 1 and 86400000, e.g. 600000 for 10 minutes.
  2. Remove the key entirely to use the 5-minute default.
  3. Convert duration strings/units to milliseconds before writing the config.
  4. Clamp large values to 86400000 if a longer effective timeout is genuinely needed (split work into multiple executions).

Example fix

// before
{ "timeoutMs": "30m" }
// after
{ "timeoutMs": 1800000 }
Defensive patterns

Strategy: validation

Validate before calling

const t = cfg.timeoutMs ?? 300_000;
if (!Number.isInteger(t) || t < 1 || t > 86_400_000) throw new Error('timeoutMs must be an integer 1..86400000 ms');

Prevention

When it happens

Trigger: Passing timeoutMs as a non-integer (e.g. 1.5), a string ("5000"), 0, a negative number, or greater than 86400000 in the CreateOS environment config, then calling parseConfig via client/config construction or the validate/probe hooks.

Common situations: Hand-editing JSON and quoting the number; entering hours-as-seconds (e.g. 172800000 for '48 hours'); pasting a duration like '30m' as a raw value; typos adding extra digits.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18). Data as JSON: /api/errors/16b3a81fe6dadae8. Report an issue: GitHub.

Appendix: source

Thrown at packages/plugins/sandbox-providers/createos/src/config.ts:36

    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 {
    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.");

View on GitHub (pinned to 3f1d897a7c)