{"record":{"id":"61fdce7240ed26c7","repo":"Significant-Gravitas/AutoGPT","slug":"failed-to-update-schedule","errorCode":null,"errorMessage":"Failed to update schedule","messagePattern":"Failed to update schedule","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedScheduleView/components/EditScheduleModal/useEditScheduleModal.ts","lineNumber":89,"sourceCode":"      if (Object.keys(errorsNow).length > 0) throw new Error(\"Invalid form\");\n\n      const cron = humanizeToCron();\n      const res = await fetch(`/api/schedules/${schedule.id}`, {\n        method: \"PATCH\",\n        headers: { \"Content-Type\": \"application/json\" },\n        body: JSON.stringify({ name, cron }),\n      });\n      if (!res.ok) {\n        let message = \"Failed to update schedule\";\n        try {\n          const data = await res.json();\n          message = data?.message || data?.detail || message;\n        } catch {\n          try {\n            message = await res.text();\n          } catch {}\n        }\n        throw new Error(message);\n      }\n      return res.json();\n    },\n    onSuccess: async () => {\n      invalidateAllScheduleQueries(queryClient, graphId);\n      const runsKey = getGetV1ListGraphExecutionsQueryKey(graphId);\n      await queryClient.invalidateQueries({ queryKey: runsKey });\n      setIsOpen(false);\n    },\n    onError: (error: any) => {\n      toast({\n        title: \"❌ Failed to update schedule\",\n        description: error?.message || \"An unexpected error occurred.\",\n        variant: \"destructive\",\n      });\n    },\n  });\n","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/Significant-Gravitas/AutoGPT/blob/9c8bb5550f446ba5d3046b78896578742495b3cf/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedScheduleView/components/EditScheduleModal/useEditScheduleModal.ts#L71-L107","documentation":"Default message thrown when PATCH /api/schedules/{id} (Next.js API route proxying the backend schedule update) returns a non-ok response. The code first tries to replace the generic message with data.message or data.detail from the JSON body, then falls back to res.text(), and only keeps 'Failed to update schedule' when the body is unparseable — so seeing the generic text usually means the route returned an empty/HTML error page (e.g. a 500 from Next itself) rather than a JSON backend error.","triggerScenarios":"PATCH /api/schedules/{id} returning 4xx/5xx: invalid cron generated by humanizeToCron (e.g. empty day selection producing '*' conflicts), schedule not found (deleted elsewhere), expired auth on the route, or backend down so the proxy returns HTML 502.","commonSituations":"Editing a schedule whose graph/schedule was deleted in another tab; backend restart during edit; a cron edge case in humanizeToCron (weekly with no days selected yields '* * * * *'-adjacent output the backend rejects); auth cookie expiry.","solutions":["Open DevTools → Network → the PATCH request: read the actual response body (message/detail) — the toast usually already shows it; the generic string only appears when the body isn't JSON or text.","If the backend rejected the cron, verify the generated expression (log humanizeToCron() output) — ensure weekly schedules always include at least one day.","Re-authenticate if the route returned 401/403.","If the response is HTML (proxy 500/502), check the Next.js server logs and that the backend container is up."],"exampleFix":"// before\nconst cron = humanizeToCron(); // weekly with 0 days -> \"m h * * *\"\n\n// after\nif (repeat === \"weekly\" && selectedDays.length === 0) {\n  setErrors({ days: \"Pick at least one day\" });\n  throw new Error(\"Invalid form\");\n}","handlingStrategy":"try-catch","validationCode":"function isValidCron(cron: string): boolean {\n  const fields = cron.trim().split(/\\s+/);\n  return fields.length === 5 && fields.every((f) => /^[\\d*,\\-/]+$/.test(f));\n}","typeGuard":"function isScheduleUpdateFailure(err: unknown): boolean {\n  return err instanceof Error && /Failed to update schedule|schedule/i.test(err.message);\n}","tryCatchPattern":"try {\n  await mutateAsync();\n} catch (error) {\n  // message already prefers server-provided data.message/data.detail\n  toast({ title: \"Failed to update schedule\", description: (error as Error).message, variant: \"destructive\" });\n}","preventionTips":["Validate the generated cron client-side (five fields, sane ranges) before PATCHing.","Always attempt to parse error body as JSON then text (as this code does) so users see backend detail, not the generic string.","Invalidate schedule queries on window focus to avoid editing deleted schedules."],"tags":["schedule","http-status","api-proxy","frontend","cron"],"backgroundTag":null,"analyzedSha":"9c8bb5550f446ba5d3046b78896578742495b3cf","analyzedAt":"2026-08-14T17:17:21.957Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}