paperclipai/paperclip · error · Error

Report campaign ID does not match publication target

Error message

Report campaign ID does not match publication target

What it means

After validating the report, createProtocolEvalBundleManifest cross-checks that the campaignId embedded in the report's campaign.json equals the campaignId argument the caller asked to publish for. A mismatch means the manifest would be filed under a different campaign than the report declares, breaking the immutable bundle addressing, so it throws.

Source

Thrown at packages/paperclip-runner/scripts/publish-runner-protocol-eval-history.mjs:254

  ) {
    throw new Error("Public report campaign metadata is invalid");
  }
  return { files, campaign };
}

export async function createProtocolEvalBundleManifest(
  reportRoot,
  campaignId,
  { viewerRoot } = {},
) {
  if (!SAFE_CAMPAIGN.test(campaignId))
    throw new Error("Unsafe protocol eval campaign ID");
  const { files, campaign } = await validatePublicProtocolEvalReport(
    reportRoot,
    { viewerRoot },
  );
  if (campaign.campaignId !== campaignId)
    throw new Error("Report campaign ID does not match publication target");
  const entries = await Promise.all(
    files.map(async (file) => {
      const absolute = resolve(reportRoot, ...file.split("/"));
      const [content, metadata] = await Promise.all([
        readFile(absolute),
        stat(absolute),
      ]);
      return {
        path: file,
        sha256: createHash("sha256").update(content).digest("hex"),
        bytes: metadata.size,
      };
    }),
  );
  return {
    schema: "paperclip.runner-protocol-eval.bundle/v1",
    campaignId,
    bundleDigest: createHash("sha256")

View on GitHub (pinned to 01ad858492)

Solutions

  1. Pass the campaign ID exactly as written in <reportRoot>/campaign.json
  2. Regenerate the report for the current run so its campaign.json matches the publication target
  3. Point reportRoot at the correct report directory for the given campaignId
  4. Read the report's campaign.json first and use its campaignId as the manifest argument

Example fix

// before
await createProtocolEvalBundleManifest("reports/old-run", "gha-99-1");
// after
const campaign = JSON.parse(await readFile("reports/old-run/campaign.json", "utf8"));
await createProtocolEvalBundleManifest("reports/old-run", campaign.campaignId);
Defensive patterns

Strategy: validation

Validate before calling

const campaign = JSON.parse(fs.readFileSync(path.join(reportRoot, "campaign.json"), "utf8"));
if (campaign.campaignId !== targetCampaignId) throw new Error(`report is for ${campaign.campaignId}, not ${targetCampaignId}`);

Try / catch

try {
  await createProtocolEvalBundleManifest(reportRoot, campaignId);
} catch (e) {
  if (String(e.message).includes("does not match publication target")) {
    const declared = JSON.parse(fs.readFileSync(path.join(reportRoot, "campaign.json"), "utf8")).campaignId;
    console.error(`report declares ${declared}; pass that id or regenerate the report`);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling createProtocolEvalBundleManifest(reportRoot, 'gha-9-1') against a reportRoot whose campaign.json says campaignId 'gha-8-2'; reusing a stale report directory while passing the current run's ID; publishing two different generated reports with a hard-coded campaign ID.

Common situations: CI retries that reuse a cached report from another attempt; locally testing the publish script with the wrong report directory; a copied/moved report directory containing another run's metadata.

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/63748cc190206ef9. Report an issue: GitHub.