paperclipai/paperclip · error · Error

Expected an original Actions campaign

Error message

Expected an original Actions campaign

What it means

After loading sourceRoot/campaign.json, refreshProtocolEvalReport asserts the campaignId matches /^gha-[1-9][0-9]*-[1-9][0-9]*$/ — i.e. it must be an original GitHub Actions-generated campaign, not a hand-made or re-published one. The error means campaign.json describes a campaign the refresher refuses to operate on.

Source

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

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({
    runsRoot: join(sourceRoot, "runs"),
    publicRunsRoot: runsRoot,
  });
  execFileSync(
    "python3",
    [
      program,

View on GitHub (pinned to 01ad858492)

Solutions

  1. Point --source at the original Actions-produced campaign directory containing a gha-<run>-<n> campaignId
  2. If the source is a refresh output, re-run from the original sourceRoot instead
  3. Fix or regenerate campaign.json so campaignId follows the gha-<number>-<number> format
  4. Confirm campaignId is present and not undefined in campaign.json

Example fix

// before
// campaign.json: { "campaignId": "my-local-campaign" }
// after
// campaign.json: { "campaignId": "gha-10293847-1" }
Defensive patterns

Strategy: validation

Validate before calling

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('Not an original Actions campaign: ' + campaign.campaignId);

Type guard

const isActionsCampaign = (c) => typeof c?.campaignId === 'string' && /^gha-[1-9][0-9]*-[1-9][0-9]*$/.test(c.campaignId);

Try / catch

try { await refreshProtocolEvalReport(opts); } catch (e) { if (e.message === 'Expected an original Actions campaign') console.error('campaign.json in', opts.sourceRoot, 'has a non-Actions campaignId'); throw e; }

Prevention

When it happens

Trigger: Pointing --source at a local, synthetic, or refreshed campaign directory whose campaignId doesn't start with 'gha-' followed by two numeric segments; campaign.json missing campaignId (undefined fails the regex).

Common situations: Running the refresher against a previously refreshed report's output instead of the original campaign snapshot; editing campaignId by hand; a legacy campaign predating the gha- naming scheme.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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