paperclipai/paperclip · error

schedule references unknown candidate ${entry.candidateId}

Error message

schedule references unknown candidate ${entry.candidateId}

What it means

Thrown by executeRunnerLiveSchedule when a schedule entry's candidateId does not match any candidate in schedule.candidates. The function builds the candidate lookup inside the execution loop and fails fast rather than silently skipping malformed schedule entries. It indicates the schedule was constructed with inconsistent entry/candidate data.

Source

Thrown at packages/paperclip-runner/src/eval/live-workflow-matrix.ts:488

export async function executeRunnerLiveSchedule(
  schedule: RunnerLiveEvalSchedule,
  execute: (
    entry: RunnerLiveScheduleEntry,
    candidate: RunnerLiveEvalCandidate,
  ) => Promise<RunnerWorkflowObservation>,
  onInfrastructureFailure?: (
    entry: RunnerLiveScheduleEntry,
    candidate: RunnerLiveEvalCandidate,
    error: RunnerWorkflowInfrastructureError,
  ) => RunnerWorkflowObservation | Promise<RunnerWorkflowObservation>,
): Promise<RunnerWorkflowObservation[]> {
  const results: RunnerWorkflowObservation[] = [];
  for (const entry of schedule.entries) {
    const resolved = schedule.candidates.find(
      (candidate) => candidate.id === entry.candidateId,
    );
    if (!resolved)
      throw new Error(
        `schedule references unknown candidate ${entry.candidateId}`,
      );
    let infrastructureAttempts = 0;
    while (true) {
      try {
        results.push(await execute(entry, resolved));
        break;
      } catch (error) {
        if (!(error instanceof RunnerWorkflowInfrastructureError)) {
          throw error;
        }
        if (!error.retryable || infrastructureAttempts >= 1) {
          if (onInfrastructureFailure === undefined) throw error;
          results.push(await onInfrastructureFailure(entry, resolved, error));
          break;
        }
        infrastructureAttempts += 1;
      }

View on GitHub (pinned to 01ad858492)

Solutions

  1. Inspect schedule.entries and schedule.candidates; make every entry.candidateId exist in candidates before calling executeRunnerLiveSchedule
  2. Fix the schedule builder so entries are generated from the same candidate list it embeds (derive entry.candidateId from candidates[i].id)
  3. If filtering candidates, filter entries with the same predicate
  4. Add a pre-call validation that every entry.candidateId is in the candidate id set

Example fix

// before
const schedule = { candidates: candidates.filter(c => c.enabled), entries: allEntries };
await executeRunnerLiveSchedule(schedule);
// after
const enabled = candidates.filter(c => c.enabled);
const schedule = { candidates: enabled, entries: allEntries.filter(e => enabled.some(c => c.id === e.candidateId)) };
await executeRunnerLiveSchedule(schedule);
Defensive patterns

Strategy: validation

Validate before calling

const ids = new Set(schedule.candidates.map(c => c.id));
const bad = schedule.entries.filter(e => !ids.has(e.candidateId));
if (bad.length) throw new Error(`entries reference unknown candidates: ${bad.map(e => e.candidateId).join(', ')}`);

Type guard

function isScheduleValid(schedule: { candidates: {id: string}[]; entries: {candidateId: string}[] }): boolean {
  const ids = new Set(schedule.candidates.map(c => c.id));
  return schedule.entries.every(e => ids.has(e.candidateId));
}

Try / catch

try {
  await executeRunnerLiveSchedule(schedule);
} catch (err) {
  if (err instanceof Error && err.message.startsWith('schedule references unknown candidate')) {
    // log the schedule and skip/rebuild
  } else throw err;
}

Prevention

When it happens

Trigger: Calling executeRunnerLiveSchedule with a LiveWorkflowSchedule where some entry.candidateId was never added to schedule.candidates (typo, filtered-out candidate, or hand-built schedule).

Common situations: Hand-assembled schedules in eval scripts; candidates deduplicated or filtered after entries were generated; candidate IDs regenerated (e.g. UUIDs) after entries referenced old IDs.

Related errors


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-02). Data as JSON: /api/errors/9086e4f3ab6a09bc. Report an issue: GitHub.