paperclipai/paperclip · error

Invalid sandbox environment variable.

Error message

Invalid sandbox environment variable.

What it means

commandScript validates every entry in params.env: keys must match /^[A-Za-z_][A-Za-z0-9_]*$/ (a valid POSIX shell identifier) and values must be strings. Anything else — keys starting with a digit, containing dashes/dots/spaces, or non-string values — is rejected to guarantee the generated 'KEY=value' shell lines are safe.

Solutions

  1. Rename env keys to valid shell identifiers: letters, digits, underscores, not starting with a digit.
  2. Coerce values with String(value) before passing them in env.
  3. Drop or whitelist unsupported keys before calling execute, e.g. Object.fromEntries(entries.filter(([k, v]) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(k) && typeof v === 'string')).

Example fix

// before
exec({ command: "make", env: { "BUILD-ID": 42 } })
// after
exec({ command: "make", env: { BUILD_ID: "42" } })
Defensive patterns

Strategy: validation

Validate before calling

const ENV_KEY_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
function sanitizeEnv(env) {
  return Object.fromEntries(
    Object.entries(env ?? {}).filter(([k, v]) => ENV_KEY_RE.test(k) && typeof v === 'string')
      .map(([k, v]) => [k, String(v)])
  );
}

Type guard

function isShellSafeEnv(env) {
  return Object.entries(env ?? {}).every(([k, v]) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(k) && typeof v === 'string');
}

Prevention

When it happens

Trigger: Calling execute with params.env containing a key like '1PATH', 'MY-VAR', 'my.var', or an empty key, or a value that is a number, boolean, object, or undefined.

Common situations: Passing through process.env from a context with odd vars (e.g. npm_lifecycle_event-like keys with dashes); passing structured config values (numbers/objects) without String() conversion; forwarding env maps from other tools with dotted keys.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


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

Appendix: source

Thrown at packages/plugins/sandbox-providers/createos/src/execute.ts:21

import { setTimeout as delay } from "node:timers/promises";
import type { PluginEnvironmentExecuteParams, PluginEnvironmentExecuteResult } from "@paperclipai/plugin-sdk";
import { CreateosApiError, CreateosClient, identifier, object } from "./client.js";

const MAX_LINE_BYTES = 1_048_576;
const MAX_CAPTURE_CHARS = 4_194_304;

export class CreateosCleanupError extends Error {}

export function shellQuote(value: string): string {
  if (value.includes("\0")) throw new Error("Sandbox command values cannot contain NUL.");
  return `'${value.replace(/'/g, `'"'"'`)}'`;
}

function commandScript(params: PluginEnvironmentExecuteParams, stdinPath: string | null): string {
  if (!params.command) throw new Error("A sandbox command is required.");
  const env = Object.entries(params.env ?? {}).map(([key, value]) => {
    if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key) || typeof value !== "string") {
      throw new Error("Invalid sandbox environment variable.");
    }
    return `${key}=${shellQuote(value)}`;
  });
  const command = [params.command, ...(params.args ?? [])].map(shellQuote).join(" ");
  return [
    params.cwd ? `cd -- ${shellQuote(params.cwd)} || exit` : "",
    `exec env ${env.join(" ")} ${command}${stdinPath ? ` < ${shellQuote(stdinPath)}` : ""}`,
  ].filter(Boolean).join("\n");
}

async function* events(response: Response): AsyncGenerator<Record<string, unknown>> {
  if (!response.body) throw new Error("CreateOS returned an empty process stream.");
  const reader = response.body.getReader();
  const decoder = new TextDecoder();
  let pending = "";
  try {
    for (;;) {
      const { value, done } = await reader.read();

View on GitHub (pinned to 3f1d897a7c)