paperclipai/paperclip · error · WatchdogDecisionApplicationError
evaluation_issue_not_found
evaluation_issue_not_found
Error message
Evaluation issue not found
What it means
When input.evaluationIssueId is supplied, createRecordWatchdogDecision fetches it company-scoped via findEvaluationIssueById; if the ID was provided but no issue is found, it throws WatchdogDecisionApplicationError with code evaluation_issue_not_found. This guards against recording decisions referencing evaluation issues that don't exist or belong to another company.
Source
Thrown at server/src/modules/active-run-watchdog/application/use-cases.ts:143
evaluationIssueId?: string | null;
reason?: string | null;
snoozedUntil?: Date | null;
createdByRunId?: string | null;
now?: Date;
};
export function createRecordWatchdogDecision(deps: RecordWatchdogDecisionDeps) {
return async function recordWatchdogDecision(
input: RecordWatchdogDecisionUseCaseInput,
): Promise<WatchdogDecisionRecord> {
const run = await deps.reader.findRunForCompany(input.companyId, input.runId);
if (!run) throw new WatchdogDecisionApplicationError("run_not_found", "Heartbeat run not found");
const evaluationIssue = input.evaluationIssueId
? await deps.reader.findEvaluationIssueById(input.companyId, input.evaluationIssueId)
: null;
if (input.evaluationIssueId && !evaluationIssue) {
throw new WatchdogDecisionApplicationError("evaluation_issue_not_found", "Evaluation issue not found");
}
if (input.actor.type === "agent" && !evaluationIssue) {
throw new WatchdogDecisionApplicationError(
"evaluation_issue_required",
"Agent watchdog decisions require the target evaluation issue",
);
}
const boardActor = input.actor.type === "board";
const assignedRecoveryOwner =
input.actor.type === "agent" &&
Boolean(input.actor.agentId) &&
evaluationIssue !== null &&
evaluationIssue.originKind === STALE_ACTIVE_RUN_EVALUATION_ORIGIN_KIND &&
evaluationIssue.originId === run.id &&
evaluationIssue.hiddenAt === null &&
!["done", "cancelled"].includes(evaluationIssue.status) &&
evaluationIssue.assigneeAgentId === input.actor.agentId;View on GitHub (pinned to 01ad858492)
Solutions
- Verify the evaluation issue ID exists and belongs to the same company via the issues API or DB query
- Refresh the issue ID from the stale-active-run evaluation issue list before recording the decision
- If the ID was optional in your flow, omit evaluationIssueId rather than passing an invalid value (but note agents must supply a valid one)
- Check whether the issue was hidden or moved, making the scoped lookup miss it
Example fix
// before
await recordWatchdogDecision({ companyId, runId, evaluationIssueId: staleIssueId, ... });
// after
const issue = await getEvaluationIssue(companyId, issueId);
if (!issue) { throw new Error('evaluation issue missing; refetch from issues list'); }
await recordWatchdogDecision({ companyId, runId, evaluationIssueId: issue.id, ... }); Defensive patterns
Strategy: validation
Validate before calling
const issue = await getEvaluationIssue(companyId, evaluationIssueId); if (!issue) throw new Error(`evaluation issue ${evaluationIssueId} not found in company ${companyId}`); Type guard
null
Try / catch
try { await recordWatchdogDecision(input); } catch (e) { if (e.code === 'evaluation_issue_not_found') { /* refetch issue from issues list; drop stale payloads */ } else throw e; } Prevention
- Refresh evaluation issue IDs from the API right before recording decisions
- Purge stale issue references from UI caches after deletes
- Never copy issue IDs between company environments
- For agents, always source evaluationIssueId from the assigned stale-active-run evaluation issue
When it happens
Trigger: recordWatchdogDecision called with a non-null evaluationIssueId that resolves to no issue within input.companyId — wrong ID, deleted/hidden issue outside query filters, or an ID from a different company.
Common situations: Stale issue IDs cached in a UI after the issue was deleted; copying issue IDs between company environments; typos in IDs from API logs; agent scripts replaying old decision payloads.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- run_not_found
- evaluation_issue_mismatch
- Unable to resolve company for plugin API route
- Job not found
- Probe found no matching Anthropic Environment
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/4c8c6abd02923e47.
Report an issue: GitHub.