{"record":{"id":"395bac0ab3eef2ee","repo":"actualbudget/actual","slug":"schedule-t-name-trim-does-not-exist","errorCode":null,"errorMessage":"Schedule ${t.name.trim()} does not exist","messagePattern":"Schedule (.+?) does not exist","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/server/budget/category-template-context.ts","lineNumber":498,"sourceCode":"    }\n    //check schedule existence (prefer scheduleId, fall back to name)\n    const activeSchedules = await getActiveSchedules();\n    const scheduleIds = new Set(activeSchedules.map(s => s.id));\n    const scheduleNames = new Set(\n      activeSchedules.map(s => s.name?.trim()).filter(Boolean),\n    );\n    templates\n      .filter(t => t.type === 'schedule')\n      .forEach(t => {\n        if (t.scheduleId) {\n          if (!scheduleIds.has(t.scheduleId)) {\n            throw new Error(\n              `Schedule ${t.name ?? t.scheduleId} does not exist`,\n            );\n          }\n        } else if (t.name) {\n          if (!scheduleNames.has(t.name.trim())) {\n            throw new Error(`Schedule ${t.name.trim()} does not exist`);\n          }\n        } else {\n          throw new Error('Schedule template has no scheduleId or name');\n        }\n      });\n    //find lowest priority\n    const lowestPriority = Math.min(\n      ...templates\n        .filter(t => t.type === 'schedule' || t.type === 'by')\n        .map(t => t.priority),\n    );\n    //warn if priority needs fixed\n    templates\n      .filter(t => t.type === 'schedule' || t.type === 'by')\n      .forEach(t => {\n        if (t.priority !== lowestPriority) {\n          throw new Error(\n            `Schedule and By templates must be the same priority level. Fix by setting all Schedule and By templates to priority level ${lowestPriority}`,","sourceCodeStart":480,"sourceCodeEnd":516,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/budget/category-template-context.ts#L480-L516","documentation":"The goal-templates engine validates every schedule template against the schedules that actually exist in the budget. When a template references a schedule by name (or by id) that is not in the budget's schedule list, initialization aborts with this error so templates cannot silently do nothing.","triggerScenarios":"A `#template schedule <name>` line (or a template object with type 'schedule'/'by' and a `name` field) is processed during budget initialization (init -> checkByAndScheduleAndSpend) and `scheduleNames.has(t.name.trim())` is false — the schedule was renamed, deleted, or never created, or the template name has inconsistent casing/whitespace not matching any schedule name.","commonSituations":"User deletes or renames a schedule after adding a schedule template line to a category note; typo in the schedule name in the category template; copying template notes between budgets where the target budget lacks the schedule; restoring an older budget file where schedules were removed.","solutions":["Open the schedule pages and confirm a schedule exists whose exact (trimmed) name matches the name in the template line, then correct the template name or the schedule name","If the schedule was deleted intentionally, remove the `#template schedule ...` line from the category note","Alternatively reference the schedule by its scheduleId instead of name, ensuring that schedule still exists"],"exampleFix":"// before\n#template schedule Paycheck Bi-Weekly\n// after (schedule renamed to \"Paycheck\")\n#template schedule Paycheck","handlingStrategy":"validation","validationCode":"const scheduleNames = new Set((await aqlQuery('SELECT * FROM schedules')).map(s => s.name));\nconst name = 'Paycheck';\nif (!scheduleNames.has(name)) throw new Error(`Template references unknown schedule: ${name}`);","typeGuard":"function hasSchedule(name, scheduleNames) {\n  return typeof name === 'string' && scheduleNames.has(name.trim());\n}","tryCatchPattern":"try {\n  await init();\n} catch (e) {\n  if (/^Schedule .* does not exist$/.test(e.message)) {\n    // fix or remove the offending schedule template line, then retry\n  } else throw e;\n}","preventionTips":["Keep schedule names and template lines in sync; update templates immediately after renaming a schedule","Reference schedules by scheduleId when stability matters more than readability","Search category notes for `#template schedule` before deleting any schedule","Trim whitespace and match casing exactly between note and schedule name"],"tags":["goal-templates","schedule","validation"],"backgroundTag":"missing-referenced-entity","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}