{"record":{"id":"b9a92fb2a581da94","repo":"actualbudget/actual","slug":"invalid-group-id","errorCode":null,"errorMessage":"Invalid group ID","messagePattern":"Invalid group ID","errorType":"exception","errorClass":"GenericFileError","httpStatus":null,"severity":"error","filePath":"packages/sync-server/src/app-sync/services/files-service.ts","lineNumber":281,"sourceCode":"      throw new GenericFileError('File not found', { id });\n    }\n    return this.validate(rawFile);\n  }\n\n  getRaw(fileId: FileId): RawFile | null {\n    return this.accountDb.first(`SELECT * FROM files WHERE id = ?`, [fileId]);\n  }\n\n  validate(rawFile: RawFile) {\n    const fileId = rawFile.id;\n    if (!isValidFileId(fileId)) {\n      throw new GenericFileError('Invalid file ID', { fileId });\n    }\n\n    let groupId: GroupId | null = null;\n    if (rawFile.group_id !== null) {\n      if (!isValidGroupId(rawFile.group_id)) {\n        throw new GenericFileError('Invalid group ID', {\n          groupId: rawFile.group_id,\n        });\n      }\n      groupId = rawFile.group_id;\n    }\n\n    return new File({\n      id: fileId,\n      name: rawFile.name,\n      groupId,\n      encryptSalt: rawFile.encrypt_salt,\n      encryptTest: rawFile.encrypt_test,\n      encryptKeyId: rawFile.encrypt_keyid,\n      encryptMeta: rawFile.encrypt_meta,\n      syncVersion: rawFile.sync_version,\n      deleted: Boolean(rawFile.deleted),\n      owner: rawFile.owner,\n    });","sourceCodeStart":263,"sourceCodeEnd":299,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/sync-server/src/app-sync/services/files-service.ts#L263-L299","documentation":"GenericFileError thrown by FilesService.validate() when the file's group_id is non-null but fails isValidGroupId(). The group ID ties the file to its CRDT sync group, so a malformed group ID makes the file unusable for sync even though its own ID may be valid.","triggerScenarios":"Rows where group_id was written in a wrong format (not the expected GroupId shape) — e.g. manual inserts, partial migrations, or tests fabricating group IDs; validate() runs inside get/find/update so any read or update of such a row throws.","commonSituations":"Dev databases seeded by hand; restoring partial backups where files rows survived but group data did not; older Actual versions with different ID formats being read by a newer server.","solutions":["Inspect the row's group_id: SELECT id, group_id FROM files WHERE id = ? and compare to the expected format.","Regenerate a valid group ID and update the row, or delete/re-create the file via the normal flow.","Avoid manual writes to the files table; use FilesService.set() which assigns valid group IDs.","If migrating from an old server, follow the documented upgrade path rather than copying rows."],"exampleFix":"// before\nUPDATE files SET group_id = 'grp' WHERE id = ?;   // invalid -> 'Invalid group ID'\n// after\nUPDATE files SET group_id = ? WHERE id = ?;       // pass a valid GroupId (uuid)","handlingStrategy":"validation","validationCode":"import { isValidGroupId } from './utils';\nconst raw = filesService.getRaw(id);\nif (raw && raw.group_id !== null && !isValidGroupId(raw.group_id)) {\n  throw new Error(`File ${id} has a corrupt group_id: ${raw.group_id}`);\n}","typeGuard":"function hasValidGroupId(raw: { group_id: string | null }): boolean {\n  return raw.group_id === null || isValidGroupId(raw.group_id);\n}","tryCatchPattern":"try {\n  return filesService.find();\n} catch (err) {\n  if (err instanceof Error && err.message === 'Invalid group ID') {\n    logger.warn('Corrupt group_id in files table; re-creating group');\n    return repairGroupIds();\n  }\n  throw err;\n}","preventionTips":["Assign group IDs only through FilesService.set().","Keep the server and client on compatible versions when migrating.","Validate group_id format in any import/restore scripts.","Back up the account DB before schema migrations."],"tags":["validation","corrupt-data","sync-server","database"],"backgroundTag":"invalid-identifier-format","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}