{"record":{"id":"58e7fdd1cdfc23e2","repo":"paperclipai/paperclip","slug":"select-an-agent-to-use-goal","errorCode":null,"errorMessage":"Select an agent to use /goal.","messagePattern":"Select an agent to use /goal\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ui/src/components/task-chat/RunnerGoalWidget.tsx","lineNumber":98,"sourceCode":"    if (next.issueId !== issueId || (agentId && next.agentId !== agentId)) return;\n    const current = queryClient.getQueryData<RunnerGoalProjection>(key);\n    if (current && next.revision > current.revision + 1) {\n      void query.refetch();\n      return;\n    }\n    if (!current || next.revision >= current.revision) queryClient.setQueryData(key, next);\n  });\n\n  const executeAction = useCallback(async (\n    action: RunnerGoalAction,\n    objective?: string,\n    confirmReplace = false,\n    expectedRevision?: number,\n  ) => {\n    setActionError(null);\n    try {\n      const current = query.data ?? (await query.refetch()).data;\n      if (!current?.agentId) throw new Error(current?.capability.reason ?? \"Select an agent to use /goal.\");\n      if (current.capability.availability !== \"available\") {\n        throw new Error(current.capability.reason ?? \"Session goals are unsupported by this agent.\");\n      }\n      await mutation.mutateAsync({\n        requestId: requestId(),\n        agentId: current.agentId,\n        expectedRevision: expectedRevision ?? current.revision,\n        action,\n        ...(objective ? { objective } : {}),\n        ...(action === \"replace\" ? { confirmReplace } : {}),\n      });\n    } catch (error) {\n      setActionError(error instanceof Error ? error.message : \"The goal action could not be applied.\");\n      throw error;\n    }\n  }, [mutation, query]);\n\n  const edit = useCallback(async () => {","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/ui/src/components/task-chat/RunnerGoalWidget.tsx#L80-L116","documentation":"useRunnerGoalControl's action handler refetches the runner goal capability query and throws when the current runner has no agentId, falling back to \"Select an agent to use /goal.\" when the backend did not provide a capability.reason. It guards the /goal feature: goals require a runner session with an assigned agent.","triggerScenarios":"Invoking a goal action (set/clear via runnerGoal.control or the widget) while the runner-goal capability query returns data with agentId null/undefined and no explanatory capability.reason — e.g. no agent selected for the runner yet.","commonSituations":"User opens the goal widget before picking an agent for the run; agent was unassigned/stopped between widget load and action; stale capability data after a session restart; first load where refetch also returns no agent.","solutions":["Select/assign an agent for the runner session, then retry the goal action.","If the runner is stopped, restart it so an agent is attached.","Refresh the widget to refetch capability data if an agent is in fact assigned.","Check backend capability reason surfaced in the UI for the underlying cause when present."],"exampleFix":"// before: acting without an assigned agent\nawait runnerGoal.control({ action: \"set\", goal });\n\n// after: pre-check before acting\nconst cap = await runnerGoal.refetch();\nif (!cap.data?.agentId) {\n  showToast(\"Select an agent before setting a goal.\");\n  return;\n}\nawait runnerGoal.control({ action: \"set\", goal });","handlingStrategy":"validation","validationCode":"const cap = useRunnerGoalCapabilityQuery(runnerId).data;\nconst canSetGoal = Boolean(cap?.agentId);\nif (!canSetGoal) disableGoalWidget(\"Select an agent to use /goal.\");","typeGuard":"const hasAgent = (cap: { agentId?: string | null } | undefined): cap is { agentId: string } =>\n  typeof cap?.agentId === \"string\" && cap.agentId.length > 0;","tryCatchPattern":"try {\n  await runnerGoal.control({ action, goal });\n} catch (e) {\n  if (e instanceof Error && e.message === \"Select an agent to use /goal.\") {\n    promptAgentSelection();\n  } else throw e;\n}","preventionTips":["Only render the goal widget after an agent is assigned to the runner.","Check capability.agentId before issuing goal actions.","Refetch capability data after session changes (restart, agent switch)."],"tags":["ui","react-query","goal","agent-session"],"backgroundTag":"missing-required-argument","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}