paperclipai/paperclip · error · Error
Public report campaign metadata is invalid
Error message
Public report campaign metadata is invalid
What it means
validatePublicProtocolEvalReport requires campaign.json to declare schema "paperclip.runner-protocol-eval.campaign/v1" and a campaignId matching SAFE_CAMPAIGN (gha-<run>-<attempt> optionally suffixed with -report-<slug>). If either check fails the report metadata cannot be trusted for immutable public publication, so the publisher refuses it. This protects the S3 history from arbitrary or forged campaign identifiers.
Source
Thrown at packages/paperclip-runner/scripts/publish-runner-protocol-eval-history.mjs:237
);
}
}
}
if (viewer) {
for (const file of viewer.files.keys())
if (!files.includes(file))
throw new Error(`Missing public viewer asset: ${file}`);
if (files.some((file) => /^attempts\/[^/]+\.html$/.test(file)))
throw new Error(
"Chat Evalbook must not mix in legacy plain attempt pages",
);
}
const campaign = await loadObject(join(root, "campaign.json"));
if (
campaign.schema !== "paperclip.runner-protocol-eval.campaign/v1" ||
!SAFE_CAMPAIGN.test(String(campaign.campaignId ?? ""))
) {
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(View on GitHub (pinned to 01ad858492)
Solutions
- Open <reportRoot>/campaign.json and confirm schema === "paperclip.runner-protocol-eval.campaign/v1"
- Set campaignId to the GHA form gha-<run_number>-<attempt> (optionally -report-<slug>, slug lowercase alnum/hyphen, max 40 chars)
- Regenerate the report with the current eval pipeline so it writes valid campaign metadata
- If testing locally, use a compliant synthetic ID like gha-1-1-test
Example fix
// before (campaign.json)
{ "schema": "campaign/v2", "campaignId": "local_run_42" }
// after
{ "schema": "paperclip.runner-protocol-eval.campaign/v1", "campaignId": "gha-42-1" } Defensive patterns
Strategy: validation
Validate before calling
const campaign = JSON.parse(fs.readFileSync(path.join(reportRoot, "campaign.json"), "utf8"));
const SAFE = /^gha-[1-9][0-9]*-[1-9][0-9]*(-report-[a-z0-9][a-z0-9-]{0,39})?$/;
if (campaign.schema !== "paperclip.runner-protocol-eval.campaign/v1" || !SAFE.test(String(campaign.campaignId)))
throw new Error("invalid campaign.json before publish"); Type guard
const isValidCampaign = (c) =>
!!c && typeof c === "object" && !Array.isArray(c) &&
c.schema === "paperclip.runner-protocol-eval.campaign/v1" &&
/^gha-[1-9][0-9]*-[1-9][0-9]*(-report-[a-z0-9][a-z0-9-]{0,39})?$/.test(String(c.campaignId ?? "")); Try / catch
try {
await publishProtocolEvalHistory({ reportRoot, destination, viewerRoot });
} catch (e) {
if (String(e.message).includes("campaign metadata is invalid")) {
console.error("check campaign.json schema/campaignId:", fs.readFileSync(path.join(reportRoot, "campaign.json"), "utf8"));
}
throw e;
} Prevention
- Always generate reports via the current eval pipeline, never hand-edit campaign.json
- Validate campaign.json in CI before the publish step
- Keep campaign IDs in the gha-<run>-<attempt> form produced by GitHub Actions
When it happens
Trigger: campaign.json missing the schema field or carrying a wrong/older schema value; campaignId absent, empty, or not matching the gha-N-N(-report-slug) pattern (e.g. a local name like 'my-eval-run' or containing uppercase/underscores); campaign.json being a JSON array or scalar (loadObject throws a different error, but a malformed object shape lands here).
Common situations: Running the publish script on a report directory produced by an outdated generator; hand-crafting a campaign.json for testing; CI environment producing a campaign ID that does not follow the GHA run/attempt convention.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Worktree seed manifest is missing source path diagnostics.
- unsupported request schema
- Public attempt must contain the read-only public chat projec
- Unknown public chat payload field
- Unknown public chat projection field
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/c1cf36bfe21dfcd5.
Report an issue: GitHub.