paperclipai/paperclip · error · Error

Applying a company import from a non-interactive terminal re

Error message

Applying a company import from a non-interactive terminal requires --yes. Use --dry-run first to inspect the preview.

What it means

Thrown by resolveCompanyImportApplyConfirmationMode when an apply is run from a non-interactive terminal (no TTY on stdin/stdout) without --yes. Without a TTY the confirmation prompt cannot be displayed, so the library blocks the destructive apply and points the caller at --dry-run.

Source

Thrown at cli/src/commands/client/company.ts:814

  url.hash = "";
  return url.toString();
}

export function resolveCompanyImportApplyConfirmationMode(input: {
  yes?: boolean;
  interactive: boolean;
  json: boolean;
}): "skip" | "prompt" {
  if (input.yes) {
    return "skip";
  }
  if (input.json) {
    throw new Error(
      "Applying a company import with --json requires --yes. Use --dry-run first to inspect the preview.",
    );
  }
  if (!input.interactive) {
    throw new Error(
      "Applying a company import from a non-interactive terminal requires --yes. Use --dry-run first to inspect the preview.",
    );
  }
  return "prompt";
}

export function isHttpUrl(input: string): boolean {
  return /^https?:\/\//i.test(input.trim());
}

export function looksLikeRepoUrl(input: string): boolean {
  try {
    const url = new URL(input.trim());
    if (url.protocol !== "https:") return false;
    const segments = url.pathname.split("/").filter(Boolean);
    return segments.length >= 2;
  } catch {
    return false;

View on GitHub (pinned to 67001ec6eb)

Solutions

  1. Add --yes to the apply command when running non-interactively.
  2. Allocate a TTY if you genuinely want the prompt (ssh -t, docker run -t -i, or run directly in a terminal).
  3. Run --dry-run first in the same environment to validate the package, then apply with --yes.
  4. In code, detect !process.stdin.isTTY up front and force yes:true before calling resolveCompanyImportApplyConfirmationMode.

Example fix

# before (cron)
0 2 * * * paperclipai company import pkg.zip --target new-company
# after
0 2 * * * paperclipai company import pkg.zip --target new-company --yes
Defensive patterns

Strategy: validation

Validate before calling

function resolveConfirmationMode(input: { yes?: boolean; interactive: boolean; json: boolean }) {
  const nonInteractive = !input.interactive;
  if (nonInteractive && !input.yes) {
    throw new Error("Non-interactive terminal: pass --yes or run interactively.");
  }
  return input.yes ? "skip" : "prompt";
}

Type guard

function isInteractiveApplyReady(input: { yes?: boolean; interactive: boolean }): boolean {
  return input.yes === true || input.interactive === true;
}

Prevention

When it happens

Trigger: Piping stdout into a file or another command, running inside cron/systemd/Docker without a pseudo-TTY, SSH non-interactive sessions, or any shell where process.stdin.isTTY or process.stdout.isTTY is false — and --yes is not set.

Common situations: Scheduled nightly imports, CI runners, containerized jobs, 'nohup' or backgrounded processes, and redirected output (>'log'). The interactive prompt worked locally but fails in the scheduled environment.

Related errors


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