{"record":{"id":"b1f92142988c7309","repo":"actualbudget/actual","slug":"schedule-template-has-no-scheduleid-or-name","errorCode":null,"errorMessage":"Schedule template has no scheduleId or name","messagePattern":"Schedule template has no scheduleId or name","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/server/budget/category-template-context.ts","lineNumber":501,"sourceCode":"    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}`,\n          );\n          //t.priority = lowestPriority;\n        }","sourceCodeStart":483,"sourceCodeEnd":519,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/budget/category-template-context.ts#L483-L519","documentation":"A schedule template line was found that carries neither a schedule name nor a scheduleId, so the engine cannot resolve it to any schedule. This is thrown as a template-syntax failure during budget initialization.","triggerScenarios":"`checkByAndScheduleAndSpend` (called from init) encounters a template of type 'schedule'/'by' where `t.name` is empty/undefined and `t.scheduleId` is missing — e.g. `#template schedule` with no argument, or a template parsed with an empty name value.","commonSituations":"Incomplete template line typed into a category note; a note-editing mishap that deletes the schedule name but leaves the directive; programmatic template generation that omits the name field.","solutions":["Add the schedule name (or scheduleId) to the template line, e.g. `#template schedule My Schedule`","Remove the incomplete template line if it is no longer needed"],"exampleFix":"// before\n#template schedule\n// after\n#template schedule Rent","handlingStrategy":"validation","validationCode":"const line = '#template schedule';\nconst parts = line.split(/\\s+/).slice(2).filter(Boolean);\nif (parts.length === 0) throw new Error('schedule template requires a name or scheduleId');","typeGuard":"function isCompleteScheduleTemplate(t) {\n  return typeof t.scheduleId === 'string' && t.scheduleId.length > 0 || typeof t.name === 'string' && t.name.trim().length > 0;\n}","tryCatchPattern":"try {\n  await init();\n} catch (e) {\n  if (e.message === 'Schedule template has no scheduleId or name') {\n    // locate the bare `#template schedule` line and complete or remove it\n  } else throw e;\n}","preventionTips":["Always include the schedule name on a `#template schedule` line","Preview parsed templates before applying budget automation","Lint category notes for directive lines missing arguments"],"tags":["goal-templates","schedule","template-syntax"],"backgroundTag":"missing-required-argument","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}