{"record":{"id":"e25615da5c074bd1","repo":"actualbudget/actual","slug":"unsupported-schedule-status-for-tooltip-schedul","errorCode":null,"errorMessage":"Unsupported schedule status for tooltip: ${scheduleStatus}","messagePattern":"Unsupported schedule status for tooltip: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/desktop-client/src/hooks/useCategoryScheduleGoalTemplateIndicator.ts","lineNumber":152,"sourceCode":"        'Missed {{scheduleName}} due {{distanceFromNow}} ({{formattedDate}})',\n        {\n          scheduleName: schedule.name,\n          distanceFromNow,\n          formattedDate,\n        },\n      );\n    case 'due':\n    case 'upcoming':\n      return t(\n        '{{scheduleName}} is due {{distanceFromNow}} ({{formattedDate}})',\n        {\n          scheduleName: schedule.name,\n          distanceFromNow: isToday ? t('today') : distanceFromNow,\n          formattedDate,\n        },\n      );\n    default:\n      throw new Error(\n        `Unsupported schedule status for tooltip: ${scheduleStatus}`,\n      );\n  }\n}\n","sourceCodeStart":134,"sourceCodeEnd":157,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/desktop-client/src/hooks/useCategoryScheduleGoalTemplateIndicator.ts#L134-L157","documentation":"getScheduleStatusDescription maps a schedule's computed status to a localized tooltip description. The switch over scheduleStatus has cases for the known statuses; the default branch throws when a status value arrives that has no tooltip mapping. This fail-fast keeps unmapped statuses from silently rendering an empty tooltip.","triggerScenarios":"A scheduleStatus value outside the handled set (e.g. 'scheduled', 'missed', or a newly added status) reaches the function — typically when schedule-goal status computation gains a new variant but the tooltip map isn't updated, or custom template code passes an unexpected status string.","commonSituations":"Version skew: schedules computed by newer loot-core code viewed in an older client; a plugin or custom report reusing the hook with its own status strings; a typo when passing a status manually.","solutions":["Log the actual scheduleStatus value and confirm it against the statuses handled in useCategoryScheduleGoalTemplateIndicator.ts","Add a case (or extend the mapping) for the new status in getScheduleStatusDescription","If it's your own code, pass only statuses produced by the shared schedule-status utility rather than hand-built strings","Wrap in try/catch and fall back to a generic tooltip text"],"exampleFix":"// before\ndefault:\n  throw new Error(`Unsupported schedule status for tooltip: ${scheduleStatus}`);\n// after\ndefault:\n  return t('Upcoming'); // safe fallback instead of throwing","handlingStrategy":"fallback","validationCode":"const KNOWN = ['scheduled','missed','completed','todo' /* match hook's statuses */];\nif (!KNOWN.includes(scheduleStatus)) return t('Upcoming');","typeGuard":"type ScheduleStatus = Parameters<typeof getScheduleStatusDescription>[0];\nfunction isScheduleStatus(v: unknown): v is ScheduleStatus {\n  return typeof v === 'string'; /* narrow against the concrete union in the hook */\n}","tryCatchPattern":"let description: string;\ntry {\n  description = getScheduleStatusDescription(status, schedule, t);\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Unsupported schedule status')) {\n    description = t('Upcoming');\n  } else throw e;\n}","preventionTips":["Derive statuses only from the shared schedule-status utility","When adding a status to the schedule logic, update the tooltip switch in the same PR","Exhaustiveness-check the switch with a never-based assert so TS flags missing cases","Test getScheduleStatusDescription against every status value"],"tags":["schedules","i18n","switch-default"],"backgroundTag":"unsupported-enum-value","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}