{"record":{"id":"57759fb02e5b2187","repo":"actualbudget/actual","slug":"category-raw-is-not-found-in-available-income","errorCode":null,"errorMessage":"Category \"${raw}\" is not found in available income categories","messagePattern":"Category \"(.+?)\" is not found in available income categories","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/server/budget/category-template-context.ts","lineNumber":562,"sourceCode":"      incomeCategories.map(c => c.name.toLocaleLowerCase()),\n    );\n    const availIds = new Set(incomeCategories.map(c => c.id));\n\n    const specialSources = new Set(['all income', 'available funds']);\n\n    pt.forEach(t => {\n      const raw = t.category;\n      const lowered = raw.toLocaleLowerCase();\n      // Accept either an income category name (text templates) or an income\n      // category id (UI-managed templates from CategoryAutocomplete).\n      if (\n        specialSources.has(lowered) ||\n        availNames.has(lowered) ||\n        availIds.has(raw)\n      ) {\n        return;\n      }\n      throw new Error(\n        `Category \\x22${raw}\\x22 is not found in available income categories`,\n      );\n    });\n  }\n\n  private checkLimit(templates: Template[]) {\n    for (const template of templates.filter(\n      t =>\n        t.type === 'simple' ||\n        t.type === 'periodic' ||\n        t.type === 'limit' ||\n        t.type === 'remainder',\n    )) {\n      let limitDef;\n      if (template.type === 'limit') {\n        limitDef = template;\n      } else {\n        if (template.limit) {","sourceCodeStart":544,"sourceCodeEnd":580,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/budget/category-template-context.ts#L544-L580","documentation":"A `#template 5% of <category>` style percentage template references a source category that does not exist among the budget's income categories (or recognized special sources like `all income` / `available funds`). The engine validates every referenced name during init and throws when the raw string matches neither a known special source, an income category name, nor an income category id.","triggerScenarios":"`checkPercentage` (called from init) processes a percent template whose source category, after lowercasing, is not in `specialSources`, `availNames`, and not in `availIds` — e.g. `#template 10% of Income` when the category is actually named \"Paychecks\" or is not flagged as an income category.","commonSituations":"Category renamed after the template was written; referencing a non-income (expense) category; typo or differing capitalization/spelling in the category name; template copied from another budget with different category names.","solutions":["Correct the template to use the exact name of an existing income category","Mark the intended category as an income category if it should be one","Use a recognized special source such as `all income` or `available funds` instead"],"exampleFix":"// before\n#template 10% of Income\n// after\n#template 10% of Paychecks","handlingStrategy":"validation","validationCode":"const incomeNames = new Set(categories.filter(c => c.is_income).map(c => c.name.toLowerCase()));\nconst src = 'Income';\nif (!incomeNames.has(src.toLowerCase())) throw new Error(`percentage source not an income category: ${src}`);","typeGuard":"function isIncomeCategory(name, categories) {\n  const c = categories.find(c => c.name.toLowerCase() === name.toLowerCase());\n  return !!c && c.is_income;\n}","tryCatchPattern":"try {\n  await init();\n} catch (e) {\n  if (e.message.includes('is not found in available income categories')) {\n    // fix the category name in the percent template or flag the category as income\n  } else throw e;\n}","preventionTips":["Copy category names exactly (or use ids) into percentage templates","Ensure the source category is marked as an income category","Use `all income` / `available funds` special sources where appropriate","Update percentage templates whenever renaming income categories"],"tags":["goal-templates","percentage","category","validation"],"backgroundTag":"missing-referenced-entity","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}