actualbudget/actual · error
Internal error: category ${categoryIdToMove} is not in a gro
Error message
Internal error: category ${categoryIdToMove} is not in a group and cannot be moved. What it means
ExpenseCategoryList throws this when the dragged category exists but has no `group` reference, which is required to reorder it relative to other categories. The component treats a group-less category as an invalid internal state that cannot be safely moved.
Source
Thrown at packages/desktop-client/src/components/mobile/budget/ExpenseCategoryList.tsx:75
borderRadius: 4,
},
})}
/>
);
},
onReorder: e => {
const [key] = e.keys;
const categoryIdToMove = key as CategoryEntity['id'];
const categoryToMove = categories.find(c => c.id === categoryIdToMove);
if (!categoryToMove) {
throw new Error(
`Internal error: category with ID ${categoryIdToMove} not found.`,
);
}
if (!categoryToMove.group) {
throw new Error(
`Internal error: category ${categoryIdToMove} is not in a group and cannot be moved.`,
);
}
const targetCategoryId = e.target.key as CategoryEntity['id'];
if (e.target.dropPosition === 'before') {
moveCategory.mutate({
id: categoryToMove.id,
groupId: categoryToMove.group,
targetId: targetCategoryId,
});
} else if (e.target.dropPosition === 'after') {
const targetCategoryIndex = categories.findIndex(
c => c.id === targetCategoryId,
);
if (targetCategoryIndex === -1) {View on GitHub (pinned to d4334cb6e6)
Solutions
- Ensure every category in the list is loaded with its group relation (check the query/select feeding `categories`).
- Assign the orphan category to a group before attempting reordering.
- Validate category data integrity after import/sync operations.
- Skip group-less categories during reorder instead of throwing.
Example fix
// before
if (!categoryToMove.group) {
throw new Error(`Internal error: category ${categoryIdToMove} is not in a group and cannot be moved.`);
}
// after
if (!categoryToMove.group) {
console.warn(`Category ${categoryIdToMove} has no group; skipping reorder`);
return;
} Defensive patterns
Strategy: validation
Validate before calling
if (!categoryToMove?.group) {
console.warn(`Category ${categoryIdToMove} has no group; skipping reorder`);
return;
} Type guard
function hasGroup(c: CategoryEntity): c is CategoryEntity & { group: NonNullable<CategoryEntity['group']> } {
return Boolean(c.group);
} Try / catch
try {
onReorder(e);
} catch (err) {
if (String(err).includes('not in a group')) {
refreshCategories();
} else {
throw err;
}
} Prevention
- Load categories with their group relation always included.
- Run data-integrity checks after import/sync to catch orphan categories.
- Never create categories without assigning a group.
- Filter out group-less categories from reorderable lists.
When it happens
Trigger: `onReorder` is called with a category whose `categoryToMove.group` is undefined/null — e.g. the category was loaded without its group relation or belongs to no group in the data model.
Common situations: Data imported or synced without group assignments; a query that selects categories without joining/including their group; a category created programmatically without a group ID.
Related errors
- Internal error: category ${categoryIdToMove} is not in a gro
- Internal error: account with ID ${targetAccountId} not found
- Internal error: category with ID ${categoryIdToMove} not fou
- Internal error: category with ID ${targetCategoryId} not fou
- Internal error: category group with ID ${draggedGroupId} not
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/dcc8bc2ec4f276df.
Report an issue: GitHub.