{"record":{"id":"dcc8bc2ec4f276df","repo":"actualbudget/actual","slug":"internal-error-category-categoryidtomove-is-no","errorCode":null,"errorMessage":"Internal error: category ${categoryIdToMove} is not in a group and cannot be moved.","messagePattern":"Internal error: category (.+?) is not in a group and cannot be moved\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/desktop-client/src/components/mobile/budget/ExpenseCategoryList.tsx","lineNumber":75,"sourceCode":"              borderRadius: 4,\n            },\n          })}\n        />\n      );\n    },\n    onReorder: e => {\n      const [key] = e.keys;\n      const categoryIdToMove = key as CategoryEntity['id'];\n      const categoryToMove = categories.find(c => c.id === categoryIdToMove);\n\n      if (!categoryToMove) {\n        throw new Error(\n          `Internal error: category with ID ${categoryIdToMove} not found.`,\n        );\n      }\n\n      if (!categoryToMove.group) {\n        throw new Error(\n          `Internal error: category ${categoryIdToMove} is not in a group and cannot be moved.`,\n        );\n      }\n\n      const targetCategoryId = e.target.key as CategoryEntity['id'];\n\n      if (e.target.dropPosition === 'before') {\n        moveCategory.mutate({\n          id: categoryToMove.id,\n          groupId: categoryToMove.group,\n          targetId: targetCategoryId,\n        });\n      } else if (e.target.dropPosition === 'after') {\n        const targetCategoryIndex = categories.findIndex(\n          c => c.id === targetCategoryId,\n        );\n\n        if (targetCategoryIndex === -1) {","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/desktop-client/src/components/mobile/budget/ExpenseCategoryList.tsx#L57-L93","documentation":"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.","triggerScenarios":"`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.","commonSituations":"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.","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."],"exampleFix":"// before\nif (!categoryToMove.group) {\n  throw new Error(`Internal error: category ${categoryIdToMove} is not in a group and cannot be moved.`);\n}\n// after\nif (!categoryToMove.group) {\n  console.warn(`Category ${categoryIdToMove} has no group; skipping reorder`);\n  return;\n}","handlingStrategy":"validation","validationCode":"if (!categoryToMove?.group) {\n  console.warn(`Category ${categoryIdToMove} has no group; skipping reorder`);\n  return;\n}","typeGuard":"function hasGroup(c: CategoryEntity): c is CategoryEntity & { group: NonNullable<CategoryEntity['group']> } {\n  return Boolean(c.group);\n}","tryCatchPattern":"try {\n  onReorder(e);\n} catch (err) {\n  if (String(err).includes('not in a group')) {\n    refreshCategories();\n  } else {\n    throw err;\n  }\n}","preventionTips":["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."],"tags":["ui","drag-and-drop","data-integrity","internal-error"],"backgroundTag":"missing-required-relation","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}