{"record":{"id":"65d4f999980ea2dc","repo":"jlcodes99/cockpit-tools","slug":"invalid-backup-json","errorCode":"invalid_backup_json","errorMessage":"invalid_backup_json","messagePattern":"invalid_backup_json","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/services/scheduledBackupService.ts","lineNumber":299,"sourceCode":"  const deleted = await cleanupAutoBackupFilesInternal(retentionDays);\n  if (deleted.length > 0) {\n    dispatchAutoBackupStateChanged();\n  }\n  return deleted;\n}\n\nexport async function openAutoBackupDir(): Promise<void> {\n  await invoke('open_auto_backup_dir');\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n  return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction resolveBackupPlatformPayload(jsonContent: string, platform: PlatformId): unknown {\n  const parsed = JSON.parse(jsonContent) as unknown;\n  if (!isRecord(parsed)) {\n    throw new Error('invalid_backup_json');\n  }\n  const accountBundle = isRecord(parsed.accounts) ? parsed.accounts : parsed;\n  if (!isRecord(accountBundle.platforms)) {\n    throw new Error('backup_accounts_missing');\n  }\n  const payload = accountBundle.platforms[platform];\n  if (!isRecord(payload)) {\n    throw new Error('backup_platform_missing');\n  }\n  return payload.exported_data ?? payload.data ?? payload.accounts ?? [];\n}\n\nexport function extractAutoBackupPlatformJson(jsonContent: string, platform: PlatformId): string {\n  const payload = resolveBackupPlatformPayload(jsonContent, platform);\n  return JSON.stringify(payload, null, 2);\n}\n\nexport function normalizeAutoBackupPlatforms(","sourceCodeStart":281,"sourceCodeEnd":317,"githubUrl":"https://github.com/jlcodes99/cockpit-tools/blob/1ed8b77992d62ca81fabf744deb0839ad361d5bf/src/services/scheduledBackupService.ts#L281-L317","documentation":"resolveBackupPlatformPayload parses a scheduled-backup file and requires the top level (or parsed.accounts) to be a JSON object. If JSON.parse succeeded but produced a non-object (array, string, number) — or the string was not valid JSON at all, in which case JSON.parse throws SyntaxError before this check — the library throws invalid_backup_json because there is no backup bundle to extract a platform payload from.","triggerScenarios":"Calling payload/extractAutoBackupPlatformJson with a file whose content is not a JSON object: an empty file, a truncated write, an array export, or a non-JSON (e.g. HTML error page) file passed as jsonContent.","commonSituations":"A backup file truncated by disk-full or process kill mid-write, user selects the wrong file (log or export list instead of backup), or a sync tool replaced the file with an HTML error page.","solutions":["JSON.parse the file yourself first and confirm the result is a non-null, non-array object before calling the API","Re-generate the backup via createManagedBackup to replace the corrupted file","Validate the file was fully written (compare size/checksum) if it came from a backup job or sync service","Verify restore is pointed at the auto-backup file, not an intermediate or unrelated export"],"exampleFix":"// before\nconst data = await payload(backuptext, 'qoder');\n// after\nlet parsed: unknown;\ntry { parsed = JSON.parse(backupText); } catch { throw new Error('file is not valid JSON'); }\nif (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n  throw new Error('backup file is not a JSON object');\n}\nconst data = await payload(backupText, 'qoder');","handlingStrategy":"validation","validationCode":"let parsed: unknown;\ntry { parsed = JSON.parse(fileText); } catch { throw new Error('Not valid JSON'); }\nconst isRecord = (v: unknown): v is Record<string, unknown> =>\n  typeof v === 'object' && v !== null && !Array.isArray(v);\nif (!isRecord(parsed)) throw new Error('Backup must be a JSON object');","typeGuard":"const isRecord = (v: unknown): v is Record<string, unknown> =>\n  typeof v === 'object' && v !== null && !Array.isArray(v);","tryCatchPattern":"try {\n  const data = await payload(backupText, platform);\n} catch (e) {\n  if (['invalid_backup_json','backup_accounts_missing','backup_platform_missing'].includes(e.message)) {\n    promptRestoreFromDifferentFile(e.message);\n  } else throw e;\n}","preventionTips":["Validate JSON parses as an object before any restore call","Detect truncated writes (file size/checksum) after backup jobs","Only feed auto-backup files into the restore path, not arbitrary exports","Regenerate backups after app version migrations"],"tags":["backup","restore","json","validation"],"backgroundTag":"invalid-backup-json","analyzedSha":"1ed8b77992d62ca81fabf744deb0839ad361d5bf","analyzedAt":"2026-09-05T09:51:41.178Z","contentChangedAt":"2026-09-05T09:51:41.178Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}