paperclipai/paperclip · error

Resume request was skipped.

Error message

Resume request was skipped.

What it means

After calling agentsApi.wakeup to resume a run whose process was lost, the code checks whether the response looks like a run (has an "id"). If it does not, the API declined to resume and returned only a message; this error is thrown with the server-provided message, defaulting to "Resume request was skipped." It surfaces a server-side skip decision (e.g. guard rails in the wakeup handler) to the UI.

Solutions

  1. Read the accompanying server message (result.message) for the concrete skip reason and address it.
  2. Refresh the run/heartbeat data and retry the resume if the state was stale.
  3. Check agent pause/concurrency/budget gates in the UI and lift them before resuming.
  4. Inspect server logs for the wakeup handler's skip branch to confirm why no run was created.

Example fix

// before
if (!("id" in result)) {
  throw new Error(result.message ?? "Resume request was skipped.");
}
// after (caller-side narrowing before throwing)
if (!("id" in result)) {
  toast.error(result.message ?? "Resume request was skipped.");
  await queryClient.invalidateQueries({ queryKey: queryKeys.heartbeats(run.companyId, run.agentId) });
  return;
}
Defensive patterns

Strategy: type-guard

Validate before calling

// nothing to validate client-side pre-call; refresh run state first
await queryClient.invalidateQueries({ queryKey: queryKeys.heartbeats(companyId, agentId) });

Type guard

const isResumedRun = (r: unknown): r is { id: string } =>
  typeof r === "object" && r !== null && "id" in r && typeof (r as { id: unknown }).id === "string";

Try / catch

try {
  const run = await resumeRun.mutateAsync();
  navigate(`/agents/${agentRouteId}/runs/${run.id}`);
} catch (e) {
  toast.error(e.message);
  await queryClient.invalidateQueries({ queryKey: queryKeys.heartbeats(companyId, agentId) });
}

Prevention

When it happens

Trigger: agentsApi.wakeup(..., { reason: "resume_process_lost_run", ... }) resolves with a payload lacking an "id" field — the backend skipped the wakeup (e.g. run no longer eligible, agent busy, stale run) and returned { message: ... } or a non-run object.

Common situations: The run was concurrently picked up or cancelled elsewhere; the agent has a max-concurrency or pause gate blocking on_demand wakeups; the run record transitioned between page load and the resume click; backend validation rejects the resume but returns 200 with a message.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-10). Data as JSON: /api/errors/981eced35d416992. Report an issue: GitHub.

Appendix: source

Thrown at ui/src/pages/AgentDetail.production.tsx:3308

    const taskId = asNonEmptyString(context.taskId);
    const taskKey = asNonEmptyString(context.taskKey);
    const commentId = asNonEmptyString(context.wakeCommentId) ?? asNonEmptyString(context.commentId);
    if (issueId) payload.issueId = issueId;
    if (taskId) payload.taskId = taskId;
    if (taskKey) payload.taskKey = taskKey;
    if (commentId) payload.commentId = commentId;
    return payload;
  }, [run.contextSnapshot, run.id]);
  const resumeRun = useMutation({
    mutationFn: async () => {
      const result = await agentsApi.wakeup(run.agentId, {
        source: "on_demand",
        triggerDetail: "manual",
        reason: "resume_process_lost_run",
        payload: resumePayload,
      }, run.companyId);
      if (!("id" in result)) {
        throw new Error(result.message ?? "Resume request was skipped.");
      }
      return result;
    },
    onSuccess: (resumedRun) => {
      queryClient.invalidateQueries({ queryKey: queryKeys.heartbeats(run.companyId, run.agentId) });
      navigate(`/agents/${agentRouteId}/runs/${resumedRun.id}`);
    },
  });

  const canRetryRun = run.status === "failed" || run.status === "timed_out";
  const retryRun = useMutation({
    mutationFn: async () => {
      return agentsApi.retryFailedRun(run.agentId, run.id, run.companyId);
    },
    onSuccess: (newRun) => {
      queryClient.invalidateQueries({ queryKey: queryKeys.heartbeats(run.companyId, run.agentId) });
      if (newRun.runId)
        navigate(`/agents/${agentRouteId}/runs/${newRun.runId}`);

View on GitHub (pinned to 3f1d897a7c)