paperclipai/paperclip · error · Error
Live roster ${rosterId} repeats a case
Error message
Live roster ${rosterId} repeats a case What it means
buildProtocolEvalCatalog maps each roster.cases entry through safeId and then checks whether the resulting list contains duplicates by comparing Set size to array length. Case IDs must be unique within a roster because each becomes a distinct eval cell keyed by '<rosterId>--<caseId>'; a duplicate would silently overwrite or double-run a cell.
Source
Thrown at packages/paperclip-runner/scripts/runner-protocol-eval-campaign.mjs:164
if (selected && !selected.has(rosterId) && !selected.has(rosterFile)) {
continue;
}
if (roster.schema !== "paperclip-runner/live-roster/v1") {
throw new Error(`Unsupported live roster schema in ${rosterFile}`);
}
if (!Array.isArray(roster.cases) || roster.cases.length === 0) {
throw new Error(`Live roster ${rosterId} has no cases`);
}
const configPath = inside(
programRoot,
resolve(rosterRoot, String(roster.config ?? "")),
`Config for ${rosterId}`,
);
const config = await loadObject(configPath);
const credentialName = credentialForConfig(config);
const cases = roster.cases.map((caseId) => safeId(caseId, "case ID"));
if (new Set(cases).size !== cases.length) {
throw new Error(`Live roster ${rosterId} repeats a case`);
}
rosters.push({
rosterId,
rosterFile,
configFile: relative(programRoot, configPath).split(sep).join("/"),
model: String(roster.model ?? config.model ?? "unknown"),
provider: String(config.provider ?? "codex"),
driver: String(config.driver ?? "codex_app_server"),
credentialName,
cases,
});
}
if (selected) {
const found = new Set(
rosters.flatMap((roster) => [roster.rosterId, roster.rosterFile]),
);
const missing = [...selected].filter((entry) => !found.has(entry));
if (missing.length > 0) {View on GitHub (pinned to 01ad858492)
Solutions
- Open the roster file and delete the duplicated case ID from 'cases'.
- Deduplicate programmatically before running: [...new Set(roster.cases)].
- If two distinct scenarios share a name, rename one case ID so each is unique.
Example fix
// before "cases": ["case-001", "case-002", "case-001"] // after "cases": ["case-001", "case-002"]
Defensive patterns
Strategy: validation
Validate before calling
const ids = roster.cases.map(String);
if (new Set(ids).size !== ids.length) {
throw new Error(`${rosterFile}: duplicate case IDs`);
} Type guard
function casesAreUnique(r) {
return Array.isArray(r.cases) && new Set(r.cases).size === r.cases.length;
} Prevention
- Generate case lists programmatically from a single source of truth instead of copy-pasting.
- Deduplicate with a Set when merging rosters from branches.
When it happens
Trigger: A live roster file's 'cases' array contains the same case ID string twice (e.g. ["case-001", "case-001"]).
Common situations: Merging roster files or case lists from two branches without deduplicating; copy-paste adding the same case twice; programmatic generation appending a case that is already listed.
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
- ${label} is not a regular file at ${canonical}.
- Claude Managed evals require exact model claude-sonnet-5
- AWS AgentCore evals require exact model global.anthropic.cla
- request.session.provider must match request.provider
- request.session.requestedModel must match request.model
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/37a01ddbc2376bf5.
Report an issue: GitHub.