actualbudget/actual · error
Category "${raw}" is not found in available income categorie
Error message
Category "${raw}" is not found in available income categories What it means
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.
Source
Thrown at packages/loot-core/src/server/budget/category-template-context.ts:562
incomeCategories.map(c => c.name.toLocaleLowerCase()),
);
const availIds = new Set(incomeCategories.map(c => c.id));
const specialSources = new Set(['all income', 'available funds']);
pt.forEach(t => {
const raw = t.category;
const lowered = raw.toLocaleLowerCase();
// Accept either an income category name (text templates) or an income
// category id (UI-managed templates from CategoryAutocomplete).
if (
specialSources.has(lowered) ||
availNames.has(lowered) ||
availIds.has(raw)
) {
return;
}
throw new Error(
`Category \x22${raw}\x22 is not found in available income categories`,
);
});
}
private checkLimit(templates: Template[]) {
for (const template of templates.filter(
t =>
t.type === 'simple' ||
t.type === 'periodic' ||
t.type === 'limit' ||
t.type === 'remainder',
)) {
let limitDef;
if (template.type === 'limit') {
limitDef = template;
} else {
if (template.limit) {View on GitHub (pinned to d4334cb6e6)
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
Example fix
// before #template 10% of Income // after #template 10% of Paychecks
Defensive patterns
Strategy: validation
Validate before calling
const incomeNames = new Set(categories.filter(c => c.is_income).map(c => c.name.toLowerCase()));
const src = 'Income';
if (!incomeNames.has(src.toLowerCase())) throw new Error(`percentage source not an income category: ${src}`); Type guard
function isIncomeCategory(name, categories) {
const c = categories.find(c => c.name.toLowerCase() === name.toLowerCase());
return !!c && c.is_income;
} Try / catch
try {
await init();
} catch (e) {
if (e.message.includes('is not found in available income categories')) {
// fix the category name in the percent template or flag the category as income
} else throw e;
} Prevention
- 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
When it happens
Trigger: `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.
Common situations: 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.
Related errors
- Cannot transfer between income and expense categories.
- Schedule ${t.name.trim()} does not exist
- Schedule and By templates must be the same priority level. F
- Target month has passed, remove or update the target month
- Only one `up to` allowed per category
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/57759fb02e5b2187.
Report an issue: GitHub.