{"record":{"id":"d16f5f753b330941","repo":"actualbudget/actual","slug":"invalid-limit-period-check-template-syntax","errorCode":null,"errorMessage":"Invalid limit period. Check template syntax","messagePattern":"Invalid limit period\\. Check template syntax","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/server/budget/category-template-context.ts","lineNumber":621,"sourceCode":"        const nextMonth = monthUtils.nextMonth(this.month);\n        let week = limitDef.start;\n        const baseLimit = amountToInteger(\n          limitDef.amount,\n          this.currency.decimalPlaces,\n        );\n        while (week < nextMonth) {\n          if (week >= this.month) {\n            this.limitAmount += baseLimit;\n          }\n          week = monthUtils.addWeeks(week, 1);\n        }\n      } else if (limitDef.period === 'monthly') {\n        this.limitAmount = amountToInteger(\n          limitDef.amount,\n          this.currency.decimalPlaces,\n        );\n      } else {\n        throw new Error('Invalid limit period. Check template syntax');\n      }\n\n      //amount is good save the rest\n      this.limitCheck = true;\n      this.limitHold = limitDef.hold ? true : false;\n      // check if the limit is already met and save the excess\n      if (this.fromLastMonth >= this.limitAmount) {\n        this.limitMet = true;\n        if (this.limitHold) {\n          this.limitExcess = 0;\n          this.toBudgetAmount = 0;\n          this.fullAmount = 0;\n        } else {\n          this.limitExcess = this.fromLastMonth - this.limitAmount;\n          this.toBudgetAmount = -this.limitExcess;\n          this.fullAmount = -this.limitExcess;\n        }\n      }","sourceCodeStart":603,"sourceCodeEnd":639,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/budget/category-template-context.ts#L603-L639","documentation":"The limit's `period` keyword must be one of daily, weekly, or monthly. When `checkLimit` (constructor) finds a period value it does not recognize, it throws, indicating the template line is malformed.","triggerScenarios":"A `up to` template specifies a period other than daily/weekly/monthly — e.g. a typo like `#template up to 100 weekley`, `yearly`, or an empty/garbled period token parsed into `limitDef.period`.","commonSituations":"Typo in the period keyword; using a period the goal-template grammar does not support (e.g. yearly/annually); template string mangled by note editing.","solutions":["Fix the period keyword to exactly one of `daily`, `weekly`, or `monthly`","If you need yearly behavior, express it with monthly amounts or a repeating `by` template instead"],"exampleFix":"// before\n#template up to 1200 yearly\n// after\n#template up to 100 monthly","handlingStrategy":"validation","validationCode":"const PERIODS = ['daily','weekly','monthly'];\nif (!PERIODS.includes(limitDef.period)) throw new Error(`invalid limit period: ${limitDef.period}`);","typeGuard":"function isValidPeriod(p) {\n  return p === 'daily' || p === 'weekly' || p === 'monthly';\n}","tryCatchPattern":"try {\n  await init();\n} catch (e) {\n  if (e.message.includes('Invalid limit period')) {\n    // correct the period keyword to daily/weekly/monthly\n  } else throw e;\n}","preventionTips":["Only use the documented keywords daily/weekly/monthly","Avoid free-typing periods; copy from working examples","Sanity-check template lines after manual note edits"],"tags":["goal-templates","limit","template-syntax","validation"],"backgroundTag":"invalid-enum-value","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}