paperclipai/paperclip · error

networkAllowlist[${index}] must be a string.

Error message

networkAllowlist[${index}] must be a string.

What it means

Thrown by parseLocalProcessNetworkAllowlist while iterating the networkAllowlist option. Each entry is required to be a string before it is forwarded to parseNetworkAllowlistEntry for hostname/port parsing. The check exists because the array is consumed from untyped config (the value parameter is typed unknown) and silently coercing non-strings would mask genuine misconfiguration.

Source

Thrown at packages/adapter-utils/src/local-process-sandbox.ts:145

    const parsed = new URL(trimmed.includes("://") ? trimmed : `https://${trimmed}`);
    if (parsed.username || parsed.password || parsed.pathname !== "/" || parsed.search || parsed.hash) {
      throw new Error("path");
    }
    hostname = parsed.hostname.toLowerCase();
    port = parsed.port || null;
  } catch {
    throw new Error(`networkAllowlist[${index}] must be a hostname, hostname:port, or origin URL.`);
  }
  if (!hostname || hostname === "*" || hostname.startsWith("*.")) {
    throw new Error(`networkAllowlist[${index}] must use an exact hostname; wildcards are not supported.`);
  }
  return { hostname, port };
}

export function parseLocalProcessNetworkAllowlist(value: unknown): string[] {
  if (!Array.isArray(value)) return [];
  return value.map((entry, index) => {
    if (typeof entry !== "string") throw new Error(`networkAllowlist[${index}] must be a string.`);
    const rule = parseNetworkAllowlistEntry(entry, index);
    return rule.port ? `${rule.hostname}:${rule.port}` : rule.hostname;
  });
}

export function parseLocalProcessNetworkScope(value: unknown): LocalProcessNetworkScope | null {
  if (value == null || value === "") return null;
  if (value === "deny" || value === "allowlist") return value;
  throw new Error('networkScope must be "deny" or "allowlist".');
}

export function parseLocalProcessFilesystemScope(value: unknown): "workspace" | null {
  if (value == null || value === "") return null;
  if (value === "workspace") return value;
  throw new Error('filesystemScope must be "workspace".');
}

function isNetworkTargetAllowed(hostname: string, port: string, rules: NetworkAllowlistRule[]): boolean {

View on GitHub (pinned to 67001ec6eb)

Solutions

  1. Inspect the failing index in the message (networkAllowlist[i]) and confirm that element is a string in the source config.
  2. Quote every entry: pass ["example.com", "example.com:443", "https://example.com"] rather than mixed types.
  3. If the array is sourced from user input, coerce or reject before calling parseLocalProcessNetworkAllowlist: entries.filter((e): e is string => typeof e === "string").
  4. Validate the array shape with a zod/JSON-schema validator on the config boundary so the failure surfaces at load time, not at sandbox spawn.

Example fix

// before
const allowlist = [443, "api.example.com"];
const parsed = parseLocalProcessNetworkAllowlist(allowlist);

// after
const allowlist = ["example.com:443", "api.example.com"];
const parsed = parseLocalProcessNetworkAllowlist(allowlist);
Defensive patterns

Strategy: validation

Validate before calling

function isValidAllowlist(value: unknown): value is string[] {
  return Array.isArray(value) && value.every((e) => typeof e === "string");
}

if (!isValidAllowlist(config.networkAllowlist)) {
  throw new Error("networkAllowlist must be an array of strings");
}
const parsed = parseLocalProcessNetworkAllowlist(config.networkAllowlist);

Type guard

function isNetworkAllowlistEntry(value: unknown): value is string {
  return typeof value === "string";
}

function assertNetworkAllowlist(value: unknown): asserts value is string[] {
  if (!Array.isArray(value) || !value.every(isNetworkAllowlistEntry)) {
    throw new Error("networkAllowlist must be string[]");
  }
}

Try / catch

try {
  const parsed = parseLocalProcessNetworkAllowlist(config.networkAllowlist);
} catch (error) {
  if (error instanceof Error && error.message.startsWith("networkAllowlist[")) {
    throw new ConfigError(`Invalid network allowlist config: ${error.message}`, { cause: error });
  }
  throw error;
}

Prevention

When it happens

Trigger: Calling parseLocalProcessNetworkAllowlist with an array containing a non-string element, e.g. a number (443), boolean, null, nested array, or plain object. The map callback hits the typeof guard at local-process-sandbox.ts:145 and throws before any URL parsing runs.

Common situations: YAML/JSON config loaded with numeric ports (networkAllowlist: [443, "example.com"]), a copy/paste that drops quotes around a hostname, or a default-export that returns an object literal instead of a string array. Also hit when adapter config is forwarded verbatim from an upstream API payload that types the field as (string | number)[].

Related errors


AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12). Data as JSON: /api/errors/7d4c08948b576abb. Report an issue: GitHub.