paperclipai/paperclip · error · ValueError
History has no latest campaign
Error message
History has no latest campaign
What it means
After schema validation, latest() reads history['latestCampaignId'] to know which campaign the published report should show. If the field is missing, null, or empty, there is no authoritative 'latest' pointer, and rather than silently falling back to an arbitrary campaign the script raises ValueError.
Solutions
- Re-run the campaign publisher so history.json includes a non-empty latestCampaignId.
- If this is a legitimate no-campaigns-yet state, guard the build: skip rendering (or emit an empty page) until a campaign exists.
- Fix the writer that publishes history to always set latestCampaignId atomically with campaigns.
- When testing offline, add latestCampaignId to your fixture matching one of campaigns[].campaignId.
Example fix
# before
history = {"schema": ..., "campaigns": [...]} # no latestCampaignId
# after
history = {"schema": ..., "latestCampaignId": "c-2026-09-18", "campaigns": [...]} Defensive patterns
Strategy: validation
Validate before calling
def has_latest(history):
return bool(history.get("latestCampaignId")) Type guard
def has_latest_campaign(history):
return isinstance(history.get("latestCampaignId"), str) and history["latestCampaignId"] != "" Try / catch
try:
values = summarize(history, kind)
except ValueError as e:
if str(e) == "History has no latest campaign":
return None # no campaigns published yet; render empty page
raise Prevention
- Only build the page once at least one campaign has been published.
- Ensure the publisher sets latestCampaignId atomically with the campaigns list.
- Validate history.json after every publish with a small schema check.
- Fixtures for tests must always include latestCampaignId.
When it happens
Trigger: A history JSON generated before any campaign ran (campaigns list empty or pointer never set), a truncated/partial upload of history.json, or a writer bug that omits latestCampaignId while still listing campaigns.
Common situations: Freshly initialized eval bucket with no campaigns yet; publisher crashed mid-update leaving history without the pointer; manually constructed fixtures for tests that forgot latestCampaignId.
Related errors
- Latest campaign is absent from history
- Missing campaign coverage flag
- Report refresh has no reliable measurement date
- Unsupported history schema
- CreateOS requires a shape from its shape catalog.
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/3ac55890b186dd42.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/evals-hub/build.py:24
import json
from pathlib import Path
from string import Template
from urllib.parse import quote, urlsplit
from urllib.request import urlopen
ORIGIN = "https://d1p6rlowie26tp.cloudfront.net"
SYSTEMS = {
"runner": ("runner-protocol-evals", "paperclip.runner-protocol-eval.history/v1"),
"product": ("runner-e2e", "paperclip.runner-e2e.history/v1"),
}
def latest(history, schema):
if history.get("schema") != schema:
raise ValueError("Unsupported history schema")
campaign_id = history.get("latestCampaignId")
if not campaign_id:
raise ValueError("History has no latest campaign")
candidates = [c for c in history["campaigns"] if
c["campaignId"] == campaign_id or
c.get("reportRevision", {}).get("sourceCampaignId") == campaign_id]
if not candidates:
raise ValueError("Latest campaign is absent from history")
# Report refreshes replace presentation, never the measurement date.
return max(candidates, key=lambda c: c.get("reportRevision", {}).get("renderedAt", c["generatedAt"]))
def public_report(url, prefix):
parsed = urlsplit(url)
if (parsed.scheme != "https" or parsed.netloc != urlsplit(ORIGIN).netloc
or not parsed.path.startswith(f"/{prefix}/campaigns/")
or parsed.query or parsed.fragment):
raise ValueError("Unexpected public report URL")
return html.escape(url, quote=True)
View on GitHub (pinned to 3f1d897a7c)