paperclipai/paperclip · error · Error

A safe, unique --revision is required

Error message

A safe, unique --revision is required

What it means

refreshProtocolEvalReport validates the --revision argument against /^[a-z0-9][a-z0-9-]{0,39}$/ before creating a new report output directory. The error means the revision was missing or contained unsafe characters (uppercase, underscores, slashes, >40 chars, leading hyphen). Revisions become directory names, so the check prevents path injection and collisions.

Source

Thrown at packages/paperclip-runner/scripts/refresh-runner-protocol-eval-report.mjs:21

import { execFileSync } from "node:child_process";
import { createHash } from "node:crypto";
import { mkdir, readFile, writeFile, lstat, readdir } from "node:fs/promises";
import { join, resolve } from "node:path";
import { sanitizeProtocolEvalRuns } from "./runner-protocol-eval-campaign.mjs";
import { validatePublicProtocolEvalReport } from "./publish-runner-protocol-eval-history.mjs";
import { sumAttemptCosts } from "./runner-protocol-eval-metrics.mjs";

export async function refreshProtocolEvalReport({
  sourceRoot,
  evalsRoot,
  viewerRoot,
  outputRoot,
  revision,
  selection,
  renderedAt = new Date().toISOString(),
}) {
  if (!/^[a-z0-9][a-z0-9-]{0,39}$/.test(revision ?? ""))
    throw new Error("A safe, unique --revision is required");
  if (await lstat(outputRoot).catch(() => null))
    throw new Error("Report refresh output must be a new directory");
  const campaign = JSON.parse(
    await readFile(join(sourceRoot, "campaign.json"), "utf8"),
  );
  if (!/^gha-[1-9][0-9]*-[1-9][0-9]*$/.test(campaign.campaignId ?? ""))
    throw new Error("Expected an original Actions campaign");
  const program = join(
    evalsRoot,
    "evals/paperclip-runner/tools/eval_program.py",
  );
  const rendererDigest = createHash("sha256")
    .update(await readFile(program))
    .digest("hex");
  await mkdir(outputRoot, { recursive: true });
  const runsRoot = join(outputRoot, "public-runs");
  const reportRoot = join(outputRoot, "report");
  await sanitizeProtocolEvalRuns({

View on GitHub (pinned to 01ad858492)

Solutions

  1. Supply --revision with lowercase alphanumeric/hyphen text, 1-40 chars, starting with a letter or digit
  2. Slugify the source string (e.g. branch name) to lowercase-hyphen form before passing
  3. For uniqueness, prefix with a run number: gha-${{ github.run_id }}-... or a date like 20260909a
  4. Check the resolved argv: the flag name must be exactly --revision

Example fix

// before
node refresh-runner-protocol-eval-report.mjs --revision feature/Fix_Bug
// after
node refresh-runner-protocol-eval-report.mjs --revision fix-bug-1234
Defensive patterns

Strategy: validation

Validate before calling

if (!/^[a-z0-9][a-z0-9-]{0,39}$/.test(revision ?? '')) throw new Error('Bad revision: ' + revision);

Type guard

const isSafeRevision = (v) => typeof v === 'string' && /^[a-z0-9][a-z0-9-]{0,39}$/.test(v);

Try / catch

try { await refreshProtocolEvalReport({ revision }); } catch (e) { if (e.message.includes('--revision is required')) console.error('Provide --revision matching ^[a-z0-9][a-z0-9-]{0,39}$'); throw e; }

Prevention

When it happens

Trigger: Running refresh-runner-protocol-eval-report.mjs without --revision, or with a revision like 'Fix_Bug#1', 'My Revision', a 50-char string, or one starting with '-'.

Common situations: A CI step interpolates a branch name (contains '/') as the revision; the flag is forgotten entirely; someone reuses a timestamp with colons from a Date string.

Understand the failure class

Background: "Unknown argument", "Invalid value", and "must be one of": invalid CLI argument errors explained — this error's family across 35 libraries.

Related errors


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