paperclipai/paperclip · error · Error
Invalid published campaign ID
Error message
Invalid published campaign ID
What it means
writeProtocolEvalPublicationLinks publishes protocol eval history links and refuses to process campaign IDs that don't match SAFE_CAMPAIGN. The error means the campaignId extracted from the publish result was missing or contained characters outside the allowlisted format, so the script aborts before writing GitHub Actions outputs to avoid injecting unsafe values into the public site URL paths.
Source
Thrown at packages/paperclip-runner/scripts/publish-runner-protocol-eval-history.mjs:554
await writeFile(index, renderProtocolEvalHistoryIndex(history, stylesheetHref));
await uploadFile(
validatedDestination.bucket,
`${validatedDestination.prefix}/index.html`,
index,
"no-cache",
);
return {
campaignId: campaign.campaignId,
bundleDigest: manifest.bundleDigest,
historySize: history.campaigns.length,
reportUrl: `${validatedDestination.publicBaseUrl}/${campaignPrefix}/index.html`,
historyUrl: `${validatedDestination.publicBaseUrl}/${validatedDestination.prefix}/index.html`,
};
}
export async function writeProtocolEvalPublicationLinks(result, environment = process.env) {
const { campaignId, reportUrl, historyUrl } = result;
if (!SAFE_CAMPAIGN.test(campaignId)) throw new Error("Invalid published campaign ID");
const safeUrl = (value) => {
const url = new URL(value);
if (url.protocol !== "https:" || url.username || url.password || /[\r\n<>]/.test(value))
throw new Error("Invalid published report URL");
return url.href;
};
const report = safeUrl(reportUrl);
const history = safeUrl(historyUrl);
if (environment.GITHUB_OUTPUT)
await appendFile(environment.GITHUB_OUTPUT, `report_url=${report}\nhistory_url=${history}\n`);
if (environment.GITHUB_STEP_SUMMARY)
await appendFile(environment.GITHUB_STEP_SUMMARY, `## Published Runner Evalbook\n\n[Open this run's Evalbook](<${report}>) · [All eval runs](<${history}>)\n\nCampaign: \`${campaignId}\`\n\nPublic replay uses the Runner Lab theme; full evidence is in the workflow artifact.\n`);
}
async function main() {
const result = await publishProtocolEvalHistory({
viewerRoot: process.env.PAPERCLIP_RUNNER_PROTOCOL_EVAL_VIEWER_DIR,
reportRoot: resolve(View on GitHub (pinned to 01ad858492)
Solutions
- Inspect the campaignId value passed in result and correct it to match SAFE_CAMPAIGN (e.g. lowercase alphanumerics/hyphens only)
- Regenerate the campaign so campaign.json gets a properly formatted campaignId
- Add a console log of result.campaignId before the throw to diagnose the actual value
- Pass the campaign ID explicitly from the workflow step rather than deriving it from an untrusted source
Example fix
// before
await writeProtocolEvalPublicationLinks({ campaignId: process.env.GITHUB_RUN_ID, ... });
// after
await writeProtocolEvalPublicationLinks({ campaignId: 'gha-12345-1', ... }); Defensive patterns
Strategy: validation
Validate before calling
if (!/^[A-Za-z0-9_-]+$/.test(campaignId)) throw new Error('campaignId fails SAFE_CAMPAIGN: ' + campaignId); Type guard
const hasSafeCampaignId = (r) => typeof r?.campaignId === 'string' && r.campaignId.length > 0;
Try / catch
try { await writeProtocolEvalPublicationLinks(result); } catch (e) { if (e.message === 'Invalid published campaign ID') { console.error('Bad campaignId:', result.campaignId); } throw e; } Prevention
- Log result.campaignId before publishing
- Validate campaign IDs at generation time, not publish time
- Never derive campaign IDs from branch names or free-form env vars
When it happens
Trigger: Calling writeProtocolEvalPublicationLinks with a result whose campaignId is undefined, empty, or fails the SAFE_CAMPAIGN regex (e.g. contains slashes, uppercase, spaces, or is a full URL instead of a bare ID).
Common situations: A CI workflow passes a run identifier or branch name instead of the campaign ID; the upstream campaign.json has a malformed or legacy campaignId; the result object was built incorrectly and the field is undefined.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Expected an original Actions campaign
- Invalid status '${String(rawStatus)}'. Must be one of: ${PLU
- "tool" is required and must be a string
- "runContext" is required and must be an object
- "runContext" must include agentId, runId, companyId, and pro
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/ed3a432545e6fe02.
Report an issue: GitHub.