{"record":{"id":"416c8a7065908659","repo":"actualbudget/actual","slug":"invalid-adjustment-percentage-parsedtemplate-ad","errorCode":null,"errorMessage":"Invalid adjustment percentage (${parsedTemplate.adjustment}%). Must be between -100% and 1000%","messagePattern":"Invalid adjustment percentage \\((.+?)%\\)\\. Must be between -100% and 1000%","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/server/budget/template-notes.ts","lineNumber":122,"sourceCode":"      const description =\n        descriptionLines.length > 0 ? descriptionLines.join('\\n') : undefined;\n      descriptionLines = [];\n\n      try {\n        const parsedTemplate: Template = parse(trimmedLine);\n\n        // Validate schedule adjustments\n        if (\n          (parsedTemplate.type === 'average' ||\n            parsedTemplate.type === 'schedule') &&\n          parsedTemplate.adjustment !== undefined\n        ) {\n          if (parsedTemplate.adjustmentType === 'percent') {\n            if (\n              parsedTemplate.adjustment <= -100 ||\n              parsedTemplate.adjustment > 1000\n            ) {\n              throw new Error(\n                `Invalid adjustment percentage (${parsedTemplate.adjustment}%). Must be between -100% and 1000%`,\n              );\n            }\n          } else if (parsedTemplate.adjustmentType === 'fixed') {\n            //placeholder for potential validation of amount/fixed adjustments\n          }\n        }\n\n        parsedTemplates.push(\n          description ? { ...parsedTemplate, description } : parsedTemplate,\n        );\n      } catch (e: unknown) {\n        const errorTemplate: Template = {\n          type: 'error',\n          directive: 'error',\n          line,\n          error: (e as Error).message,\n        };","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/budget/template-notes.ts#L104-L140","documentation":"Actual Budget's budget templates (the `#template` directives in category notes) support an `adjust` directive that can take a percentage. When the template is parsed during `getCategoriesWithTemplates`, the parsed adjustment value is validated: percentages are rejected if they are <= -100 (which would zero out or invert the category budget incoherently) or > 1000 (an implausible multiplier). The library throws this error to surface a malformed template directive in a category's notes rather than silently producing a wrong budget amount.","triggerScenarios":"Calling `getCategoriesWithTemplates` (directly or via `categoriesWithTemplates`/`categoryWithTemplates`) while one or more category notes contain a template directive like `#template adjust 2000%` (above 1000) or `#template adjust -150%` (at or below -100). Any budget action that reads templates with such a note triggers the throw.","commonSituations":"A user hand-edits category notes and typos an extra zero (e.g. `10000%` instead of `1000%`); a synced budget imported from another device contains a directive written before validation existed; a template-sharing workflow copies an extreme directive between budgets; a user misunderstands the allowed range and tries `-100%` expecting 'remove all budgeted amount'.","solutions":["Open the category notes in the affected budget and fix the `#template adjust` directive so its percentage is in the valid range (-100% < p <= 1000%, exclusive of -100, inclusive of 1000).","If you only need to drop a category's budget to zero, use `#template 0` or a fixed-amount adjust rather than `adjust -100%`.","If the bad note came from a sync/restore, correct the note on the source device or delete the directive before re-syncing.","Wrap the template-reading call in a try/catch during migration/import scripts so one bad note can be reported to the user with the category name instead of aborting the whole operation."],"exampleFix":"// before (category note)\n#template adjust -100%\n\n// after\n#template adjust -50%","handlingStrategy":"validation","validationCode":"function isValidAdjustPercent(pct) {\n  return typeof pct === 'number' && Number.isFinite(pct) && pct > -100 && pct <= 1000;\n}\n// scan category notes before syncing/importing:\n// for each note, extract /#template\\s+adjust\\s+(-?[\\d.]+)%/ and assert isValidAdjustPercent(parseFloat(m[1]))","typeGuard":"function isWithinAdjustRange(value) {\n  return typeof value === 'number' && Number.isFinite(value) && value > -100 && value <= 1000;\n}","tryCatchPattern":null,"preventionTips":["Keep `#template adjust` percentages in (-100%, 1000%]; remember -100% itself is rejected","Use `#template 0` or fixed amounts when you want to zero a category instead of extreme percentages","Lint/scan category notes for template directives in migration or template-sharing scripts","Test templates in a scratch budget before syncing them to production budgets"],"tags":["budget","template-validation","input-validation"],"backgroundTag":"invalid-template-parameter","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}