paperclipai/paperclip · error

PAPERCLIP_OPENCODE_RUNTIME_DIR is required

Error message

PAPERCLIP_OPENCODE_RUNTIME_DIR is required

What it means

The OpenCode app-server proxy locates its runtime working directory exclusively through the PAPERCLIP_OPENCODE_RUNTIME_DIR environment variable; runtimeDirectory() throws if the variable is unset or only whitespace, because the proxy cannot function without a resolved runtime directory.

Source

Thrown at packages/paperclip-runner/src/cli/opencode-app-server-proxy.ts:81

  return new Promise((resolveValue, reject) =>
    pending.set(id, { resolve: resolveValue, reject }),
  );
}

function record(value: unknown): Record<string, unknown> {
  return typeof value === "object" && value !== null && !Array.isArray(value)
    ? (value as Record<string, unknown>)
    : {};
}

function text(value: unknown, fallback = ""): string {
  return typeof value === "string" ? value : fallback;
}

function runtimeDirectory(): string {
  const configured = process.env.PAPERCLIP_OPENCODE_RUNTIME_DIR?.trim();
  if (!configured)
    throw new Error("PAPERCLIP_OPENCODE_RUNTIME_DIR is required");
  return resolve(configured);
}

async function open(
  params: Record<string, unknown>,
  resume: boolean,
): Promise<Record<string, unknown>> {
  if (session)
    return threadResponse(
      session.ids().providerSessionId ?? session.ids().driverSessionId,
    );
  cwd = resolve(text(params.cwd, process.cwd()));
  const model = text(params.model);
  if (!model.includes("/"))
    throw new Error("OpenCode proxy requires model in provider/model form");
  activeModel = model;
  const dynamicTools = Array.isArray(params.dynamicTools)
    ? params.dynamicTools.map(record)

View on GitHub (pinned to 01ad858492)

Solutions

  1. Export PAPERCLIP_OPENCODE_RUNTIME_DIR to the runtime directory path before starting the proxy
  2. Ensure the supervisor (runnerd) passes its full env to the child process
  3. Fail fast in the launcher if the var is absent, with a clear message

Example fix

// before
spawn('opencode-app-server-proxy', args);
// after
spawn('opencode-app-server-proxy', args, { env: { ...process.env, PAPERCLIP_OPENCODE_RUNTIME_DIR: runtimeDir } });
Defensive patterns

Strategy: validation

Validate before calling

if (!process.env.PAPERCLIP_OPENCODE_RUNTIME_DIR?.trim()) throw new Error('set PAPERCLIP_OPENCODE_RUNTIME_DIR before starting the proxy');

Type guard

function hasRuntimeDir(env: NodeJS.ProcessEnv): env is NodeJS.ProcessEnv & { PAPERCLIP_OPENCODE_RUNTIME_DIR: string } {
  return typeof env.PAPERCLIP_OPENCODE_RUNTIME_DIR === 'string' && env.PAPERCLIP_OPENCODE_RUNTIME_DIR.trim().length > 0;
}

Try / catch

try { await proxy.handle(req); }
catch (e) { if (String(e.message).includes('PAPERCLIP_OPENCODE_RUNTIME_DIR is required')) { console.error('Start via runnerd or export PAPERCLIP_OPENCODE_RUNTIME_DIR'); } else throw e; }

Prevention

When it happens

Trigger: Calling open() (directly or via handle) when process.env.PAPERCLIP_OPENCODE_RUNTIME_DIR is missing, empty, or contains only spaces.

Common situations: Launching the proxy outside the runnerd-supervised environment; a spawn wrapper forgetting to forward the parent's env; shell running with a sanitized environment (systemd, cron, CI).

Understand the failure class

Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10). Data as JSON: /api/errors/12840d5756efb65e. Report an issue: GitHub.