{"record":{"id":"77f53dcbc97ac4ff","repo":"paperclipai/paperclip","slug":"retry-was-skipped-77f53d","errorCode":null,"errorMessage":"Retry was skipped.","messagePattern":"Retry was skipped\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ui/src/pages/AgentDetail.production.tsx","lineNumber":3326,"sourceCode":"    if (!context) return payload;\n    const issueId = asNonEmptyString(context.issueId);\n    const taskId = asNonEmptyString(context.taskId);\n    const taskKey = asNonEmptyString(context.taskKey);\n    if (issueId) payload.issueId = issueId;\n    if (taskId) payload.taskId = taskId;\n    if (taskKey) payload.taskKey = taskKey;\n    return payload;\n  }, [run.contextSnapshot]);\n  const retryRun = useMutation({\n    mutationFn: async () => {\n      const result = await agentsApi.wakeup(run.agentId, {\n        source: \"on_demand\",\n        triggerDetail: \"manual\",\n        reason: \"retry_failed_run\",\n        payload: retryPayload,\n      }, run.companyId);\n      if (!(\"id\" in result)) {\n        throw new Error(result.message ?? \"Retry was skipped.\");\n      }\n      return result;\n    },\n    onSuccess: (newRun) => {\n      queryClient.invalidateQueries({ queryKey: queryKeys.heartbeats(run.companyId, run.agentId) });\n      navigate(`/agents/${agentRouteId}/runs/${newRun.id}`);\n    },\n  });\n\n  const { data: touchedIssues } = useQuery({\n    queryKey: queryKeys.runIssues(run.id),\n    queryFn: () => activityApi.issuesForRun(run.id),\n  });\n  const touchedIssueIds = useMemo(\n    () => Array.from(new Set((touchedIssues ?? []).map((issue) => issue.issueId))),\n    [touchedIssues],\n  );\n","sourceCodeStart":3308,"sourceCodeEnd":3344,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/ui/src/pages/AgentDetail.production.tsx#L3308-L3344","documentation":"Same guard as the resume path but for retrying a failed run: agentsApi.wakeup with reason \"retry_failed_run\" should return a new run object containing \"id\". If the server responds without an id, the retry was skipped server-side and this error is thrown, falling back to the server's message. It converts a soft skip response into a visible mutation error.","triggerScenarios":"agentsApi.wakeup(..., { reason: \"retry_failed_run\", ... }) resolves with an object lacking \"id\" — the backend refused to spawn the retry run and returned only a message or non-run shape.","commonSituations":"The failed run was already retried or deleted concurrently; the agent is paused or over budget so on_demand wakeups are rejected; the run's state changed between listing and clicking Retry; server validation rejects the payload.","solutions":["Check result.message for the server's skip reason and fix that underlying cause (pause, budget, concurrency).","Refresh heartbeats/run data and retry if the click acted on stale state.","Unpause the agent or free budget/concurrency slots, then Retry again.","Verify server logs for the wakeup skip branch for reason \"retry_failed_run\"."],"exampleFix":"// before\nif (!(\"id\" in result)) {\n  throw new Error(result.message ?? \"Retry was skipped.\");\n}\n// after (caller-side handling)\nif (!(\"id\" in result)) {\n  toast.error(result.message ?? \"Retry was skipped — check that the agent is not paused.\");\n  return;\n}","handlingStrategy":"type-guard","validationCode":"// refresh run state before offering Retry\nawait queryClient.invalidateQueries({ queryKey: queryKeys.heartbeats(companyId, agentId) });","typeGuard":"const isNewRun = (r: unknown): r is { id: string } =>\n  typeof r === \"object\" && r !== null && \"id\" in r && typeof (r as { id: unknown }).id === \"string\";","tryCatchPattern":"try {\n  const newRun = await retryRun.mutateAsync();\n  navigate(`/agents/${agentRouteId}/runs/${newRun.id}`);\n} catch (e) {\n  toast.error(e.message);\n}","preventionTips":["Disable Retry for runs not currently in a failed state (re-check on render).","Surface agent pause/budget gates so users lift them before retrying.","Invalidate heartbeat queries after any state-changing action to avoid stale retries."],"tags":["ui","api-response","retry","run-lifecycle"],"backgroundTag":"unexpected-api-response-shape","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"}