paperclipai/paperclip · error · WatchdogDecisionApplicationError

evaluation_issue_required

evaluation_issue_required

Error message

Agent watchdog decisions require the target evaluation issue

What it means

Agents are only permitted to record watchdog decisions when a target evaluation issue is present in the input; if input.actor.type === 'agent' and no evaluation issue resolved, the use case throws code evaluation_issue_required. The board may record decisions without an evaluation issue, but agents cannot — the issue is their authorization anchor (they must be its assignee).

Source

Thrown at server/src/modules/active-run-watchdog/application/use-cases.ts:146

  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;
    if (!boardActor && !assignedRecoveryOwner) {
      throw new WatchdogDecisionApplicationError(
        "not_authorized",

View on GitHub (pinned to 01ad858492)

Solutions

  1. Always include a valid evaluationIssueId when calling as an agent, sourced from the stale-active-run evaluation issue assigned to the agent
  2. Confirm the agent is the assignee of a visible, open (not done/cancelled) stale-active-run evaluation issue for the run
  3. If no evaluation issue exists, have a board actor record the decision instead
  4. Check that the issue's hiddenAt is null and status is not done/cancelled, which would cause the resolved issue to be rejected downstream

Example fix

// before (agent call without issue)
await recordWatchdogDecision({ actor: { type: 'agent', agentId }, companyId, runId });
// after
await recordWatchdogDecision({ actor: { type: 'agent', agentId }, companyId, runId, evaluationIssueId: assignedIssueId });
Defensive patterns

Strategy: validation

Validate before calling

if (actor.type === 'agent' && !evaluationIssueId) throw new Error('agent watchdog decisions require evaluationIssueId');

Type guard

function agentInputRequiresIssue(input: { actor: { type: string }; evaluationIssueId?: string }) { return !(input.actor.type === 'agent' && !input.evaluationIssueId); }

Try / catch

null

Prevention

When it happens

Trigger: An agent-key authenticated request calls recordWatchdogDecision without evaluationIssueId, or with one that resolved to null (which then hits this check after the not-found check), so the agent has no evaluation issue to bind its decision to.

Common situations: Agent scripts recording recovery decisions without including the evaluation issue from the stale-active-run notification; agents operating after their evaluation issue was closed (done/cancelled) or hidden so the lookup returns null; misconfigured automation calling with board-style payloads.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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