{"record":{"id":"26fc2981e16405d3","repo":"paperclipai/paperclip","slug":"name-a-different-agent-to-review-this-task-a-worker-cannot","errorCode":null,"errorMessage":"Name a different agent to review this task. A worker cannot review its own completion.","messagePattern":"Name a different agent to review this task\\. A worker cannot review its own completion\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/src/services/native-runtime/native-completion-feedback.ts","lineNumber":152,"sourceCode":"  if (issue.executionState?.status === \"pending\") {\n    return `Completion report accepted; the task's configured review stage is still pending. Explain the required review on [this task](/issues/${issue.identifier ?? issue.id}); do not say the task is done.`;\n  }\n  const readiness = await issueService(db).getDependencyReadiness(issue.id, db);\n  if (readiness.unresolvedBlockerCount > 0) {\n    return `Completion report accepted; this task still has unresolved dependencies. Explain the blockers on [this task](/issues/${issue.identifier ?? issue.id}); do not say the task is done.`;\n  }\n  if (\n    result.reportedWorkDisposition === \"needs_review\" &&\n    signals.actionableAttentionRequests.length === 0\n  ) {\n    throw new Error(\n      \"needs_review requires a concrete decision and a named reviewer in attentionRequests. Continue unfinished work or checks; report done when complete. Paperclip will not create an automatic completion approval.\",\n    );\n  }\n  for (const request of signals.actionableAttentionRequests) {\n    if (request.ownerClass !== \"agent\") continue;\n    if (request.targetAgentId === run.agentId) {\n      throw new Error(\"Name a different agent to review this task. A worker cannot review its own completion.\");\n    }\n    if (!request.targetAgentId || !/^[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i.test(request.targetAgentId)) {\n      throw new Error(\"Name the reviewer's exact agent ID in targetAgentId.\");\n    }\n    const reviewer = await db.select().from(agents).where(and(\n      eq(agents.id, request.targetAgentId), eq(agents.companyId, run.companyId),\n    )).limit(1).then((rows) => rows[0]);\n    if (!reviewer || !(await evaluateAgentInvokabilityFromDb(db, reviewer)).invokable) {\n      throw new Error(\"The named reviewer is not available in this company. Choose an available reviewer or report the concrete blocker.\");\n    }\n  }\n  return \"Completion report accepted. Task status will be committed after this turn and workspace finalization finish. Describe the completed work and any explicitly requested reviewer action; do not claim an approval is needed unless one was requested.\";\n}\n","sourceCodeStart":134,"sourceCodeEnd":166,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/server/src/services/native-runtime/native-completion-feedback.ts#L134-L166","documentation":"Within needs_review handling, each actionable agent-owned attention request must name a reviewer other than the reporting run's own agent. If targetAgentId equals run.agentId, the agent is attempting to review its own work, which the control plane forbids, and this error is thrown.","triggerScenarios":"An attention request with ownerClass 'agent' whose targetAgentId is identical to the completing run's agentId, submitted with a needs_review completion report.","commonSituations":"Adapters auto-filling targetAgentId from the current agent's ID; agents listing themselves as reviewer because no teammate was configured; template code copying run.agentId into the request.","solutions":["Set targetAgentId to a different agent in the same company (e.g. a designated reviewer agent).","If only one agent exists, request a human reviewer (ownerClass other than 'agent') or report done/blocked instead.","Fix adapter logic that defaults targetAgentId to the reporting agent's own ID.","Look up reviewer agents in the company roster before building the attention request."],"exampleFix":"// before\nattentionRequests.push({ ownerClass: \"agent\", targetAgentId: run.agentId });\n// after\nconst reviewer = pickReviewerAgentExcluding(run.agentId);\nattentionRequests.push({ ownerClass: \"agent\", targetAgentId: reviewer.id });","handlingStrategy":"validation","validationCode":"for (const r of result.attentionRequests) {\n  if (r.ownerClass === \"agent\" && r.targetAgentId === run.agentId) {\n    throw new Error(\"cannot name the reporting agent as its own reviewer\");\n  }\n}","typeGuard":"const namesExternalReviewer = (r: { ownerClass: string; targetAgentId?: string }, selfAgentId: string): boolean => r.ownerClass !== \"agent\" || (!!r.targetAgentId && r.targetAgentId !== selfAgentId);","tryCatchPattern":"try { await reportCompletion({ runId, result }); } catch (e) { if (e.message.startsWith(\"Name a different agent\")) { swapReviewerToDistinctAgent(result.attentionRequests, run.agentId); return reportCompletion({ runId, result }); } throw e; }","preventionTips":["Select reviewers from the company roster excluding the reporting agent.","Never default targetAgentId to run.agentId in adapter code.","Validate targetAgentId is a UUID of an existing same-company agent before submitting."],"tags":["validation","review-gate","self-review"],"backgroundTag":"invalid-argument-value","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}