{"record":{"id":"1a9d7be7a883d73e","repo":"paperclipai/paperclip","slug":"replacement-required","errorCode":"replacement_required","errorMessage":"replacement_required","messagePattern":"replacement_required","errorType":"error_code","errorClass":"RunnerGoalConflictError","httpStatus":null,"severity":"error","filePath":"server/src/services/runner-goals.ts","lineNumber":437,"sourceCode":"        : request.action === \"resume\"\n          ? \"resume\"\n          : request.action === \"clear\"\n            ? \"clear\"\n            : \"set\";\n      if (capability.availability !== \"available\" || !capability.actions.includes(requiredCapabilityAction)) {\n        throw new RunnerGoalActionError(\n          capability.reasonCode ?? \"goal_action_unsupported\",\n          capability.reason ?? `${request.action} is unsupported by this agent session.`,\n        );\n      }\n      if (request.tokenBudget != null && !capability.tokenBudgetControl) {\n        throw new RunnerGoalActionError(\n          \"goal_token_budget_unsupported\",\n          \"This agent session does not support goal token budgets.\",\n        );\n      }\n      if (request.action === \"create\" && currentGoal && currentGoal.status !== \"complete\") {\n        throw new RunnerGoalConflictError(\"replacement_required\", currentProjection);\n      }\n      if ([\"edit\", \"replace\", \"pause\", \"resume\", \"clear\"].includes(request.action) && !currentGoal) {\n        throw new RunnerGoalActionError(\"goal_not_found\", \"There is no current session goal.\");\n      }\n\n      const nextRevision = session.goalRevision + 1;\n      const desiredState = request.action === \"pause\"\n        ? \"paused\"\n        : request.action === \"clear\"\n          ? null\n          : \"active\";\n      await tx.update(agentTaskSessions).set({\n        goalDesiredState: desiredState,\n        goalRevision: nextRevision,\n        updatedAt: new Date(),\n      }).where(eq(agentTaskSessions.id, session.id));\n      const pendingProjection: RunnerGoalProjection = {\n        ...currentProjection,","sourceCodeStart":419,"sourceCodeEnd":455,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/runner-goals.ts#L419-L455","documentation":"Only one active goal may exist per session. If `request.action === \"create\"` and the session already has a goal whose `status !== \"complete\"`, `act` throws RunnerGoalConflictError with code `replacement_required`. The client must explicitly replace (or clear) the existing goal instead of creating a second one.","triggerScenarios":"Sending action 'create' when `storedGoal(session)` returns a live goal (status pending/active/paused, not complete); double-clicking create; automated goal seeding that runs more than once; previous goal never completed and code assumes clean slate.","commonSituations":"Retry after a partially-processed create that actually stored the goal; UI lacking goal state refresh; scripts that assume idempotent creates without consulting the projection's currentGoal.","solutions":["Use action 'replace' (or edit) instead of 'create' to swap an existing active goal","Clear the existing goal first, then create the new one after complete/clear","Read the projection's currentGoal and only 'create' when it is null or complete","On this conflict, refresh the projection and decide based on the actual current goal"],"exampleFix":"// before\nawait act(companyId, issueId, { agentId, action: 'create', goal: newGoal, ... });\n// after\nconst proj = await projection(companyId, issueId, agentId);\nconst action = proj.currentGoal && proj.currentGoal.status !== 'complete' ? 'replace' : 'create';\nawait act(companyId, issueId, { agentId, action, goal: newGoal, ... });","handlingStrategy":"type-guard","validationCode":"const proj = await runnerGoals.projection(companyId, issueId, agentId);\nconst action = proj.currentGoal && proj.currentGoal.status !== 'complete' ? 'replace' : 'create';","typeGuard":"function canCreateGoal(proj) {\n  return proj?.currentGoal == null || proj.currentGoal.status === 'complete';\n}","tryCatchPattern":"try {\n  await runnerGoals.act(companyId, issueId, req);\n} catch (e) {\n  if (e instanceof RunnerGoalConflictError && e.code === 'replacement_required') {\n    return await runnerGoals.act(companyId, issueId, { ...req, action: 'replace' });\n  }\n  throw e;\n}","preventionTips":["Check the projection's currentGoal before issuing 'create'","Make goal seeding idempotent (skip when an active goal exists)","Use 'replace' or 'edit' for changing an active goal","Disable the create control while a goal is active"],"tags":["conflict","goal","state","duplicate"],"backgroundTag":"invalid-state-transition","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}