paperclipai/paperclip · error

Pass exactly one of ${firstName} or ${secondName}.

Error message

Pass exactly one of ${firstName} or ${secondName}.

What it means

Thrown by exactlyOneFlag() when two mutually-exclusive boolean flags are both set or both unset. It enforces exclusive choice semantics in the pipelines CLI (e.g. --accept vs --dismiss). The check coerces both values with Boolean() and errors when they compare equal, so passing neither is just as wrong as passing both.

Source

Thrown at cli/src/commands/pipelines.ts:730

  const parsed = Number(value);
  if (!Number.isInteger(parsed) || parsed <= 0) throw new Error(`Invalid ${label}: ${value}`);
  return parsed;
}

function parseCsv(value: string): string[] {
  return value.split(",").map((item) => item.trim()).filter(Boolean);
}

function setIfDefined(target: JsonObject, key: string, value: unknown): void {
  if (value !== undefined) target[key] = value;
}

function looksLikeUuid(value: string): boolean {
  return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
}

function exactlyOneFlag(first: boolean | undefined, second: boolean | undefined, firstName: string, secondName: string): string {
  if (Boolean(first) === Boolean(second)) throw new Error(`Pass exactly one of ${firstName} or ${secondName}.`);
  return first ? firstName : secondName;
}

function reviewDecisionFromOptions(opts: ReviewOptions): "approve" | "reject" | "request_changes" {
  const selected = [
    opts.approve ? { flag: "--approve", decision: "approve" as const } : null,
    opts.reject ? { flag: "--reject", decision: "reject" as const } : null,
    opts.requestChanges ? { flag: "--request-changes", decision: "request_changes" as const } : null,
  ].filter((item): item is NonNullable<typeof item> => item !== null);
  if (selected.length !== 1) {
    throw new Error("Pass exactly one of --approve, --reject, or --request-changes.");
  }
  return selected[0]!.decision;
}

function printPipeline(row: PipelineDetail | PipelineSummary | null, ctx: ResolvedClientContext): void {
  if (!row) return printOutput(null, { json: ctx.json });
  if (ctx.json) return printOutput(row, { json: true });

View on GitHub (pinned to 67001ec6eb)

Solutions

  1. Pass exactly one of the two named flags, removing the other.
  2. If you genuinely want neither, you are likely calling the wrong subcommand — check the command's help (`--help`).
  3. Audit wrapper scripts that build flag lists conditionally to ensure mutual exclusion.

Example fix

// before
paperclipai pipelines transition <id> --accept --dismiss
// after
paperclipai pipelines transition <id> --accept
Defensive patterns

Strategy: validation

Validate before calling

function pickOne<T extends string>(flags: Array<[unknown, T]>, names: [T, T]): T {
  const set = flags.filter(([, v]) => Boolean(v));
  if (set.length !== 1) throw new Error(`Pass exactly one of ${names[0]} or ${names[1]}.`);
  return set[0][1];
}

Prevention

When it happens

Trigger: Running a pipelines command that calls exactlyOneFlag (line 566: accept/dismiss) with both `--accept --dismiss`, or with neither flag. The producer is `exactlyOneFlag(opts.accept, opts.dismiss, "--accept", "--dismiss")`.

Common situations: Operators confused about which acknowledgement flag to use, or shell scripts that conditionally add both flags. Also occurs when a default-true flag in a wrapper combines with an explicit override.

Related errors


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