{"record":{"id":"435e54555ded6d21","repo":"actualbudget/actual","slug":"invalid-dashboard-widgets-data-type-it-must-be-an","errorCode":null,"errorMessage":"Invalid dashboard.widgets data type: it must be an array of widgets.","messagePattern":"Invalid dashboard\\.widgets data type: it must be an array of widgets\\.","errorType":"validation","errorClass":"ValidationError","httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/server/dashboard/app.ts","lineNumber":57,"sourceCode":"    'budget-analysis-card',\n    'markdown-card',\n    'summary-card',\n    'calendar-card',\n    'formula-card',\n    'custom-report',\n    'sankey-card',\n    'balance-forecast-card',\n    'age-of-money-card',\n    'monte-carlo-card',\n  ].includes(type);\n}\n\nconst exportModel = {\n  validate(dashboard: ExportImportDashboard) {\n    requiredFields('Dashboard', dashboard, ['version', 'widgets']);\n\n    if (!Array.isArray(dashboard.widgets)) {\n      throw new ValidationError(\n        'Invalid dashboard.widgets data type: it must be an array of widgets.',\n      );\n    }\n\n    dashboard.widgets.forEach((widget, idx) => {\n      requiredFields(`Dashboard widget #${idx}`, widget, [\n        'type',\n        'x',\n        'y',\n        'width',\n        'height',\n        ...(isExportedCustomReportWidget(widget) ? ['meta' as const] : []),\n      ]);\n\n      if (!Number.isInteger(widget.x)) {\n        throw new ValidationError(\n          `Invalid widget.${idx}.x data-type for value ${widget.x}.`,\n        );","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/dashboard/app.ts#L39-L75","documentation":"The dashboard export/import validator requires dashboard.widgets to be an array. During importDashboard (or validating an exported dashboard), if the parsed JSON has widgets missing or set to a non-array (object, string, null), a ValidationError with this message is thrown before any data is written.","triggerScenarios":"Importing a dashboard JSON file where the top-level object lacks a widgets key, has widgets as a single widget object instead of an array, or the file is a different export format (e.g. an old custom-report export pasted in).","commonSituations":"Hand-edited dashboard export losing the widgets field; exporting one widget and importing the widget object directly; JSON schema drift between Actual versions.","solutions":["Open the dashboard JSON and ensure it has version and widgets: [ ... ] at the top level.","Wrap a single widget in an array: { \"widgets\": [widget] } instead of { \"widgets\": widget }.","Re-export the dashboard from a current Actual version to get a valid schema.","Validate the file with JSON.parse and Array.isArray(data.widgets) before importing.","If migrating from an old export, transform the payload into the current ExportImportDashboard shape first."],"exampleFix":"// before\nconst data = JSON.parse(text);\nawait send('dashboard-import', data); // data.widgets is an object\n// after\nconst data = JSON.parse(text);\nif (!Array.isArray(data.widgets)) {\n  data.widgets = data.widgets ? [data.widgets] : [];\n}\nawait send('dashboard-import', data);","handlingStrategy":"validation","validationCode":"const data = JSON.parse(text);\nif (!data || typeof data !== 'object' || !Array.isArray(data.widgets)) {\n  throw new Error('Dashboard import file must contain a widgets array');\n}","typeGuard":"function isDashboardImport(d: unknown): d is { version: number; widgets: unknown[] } {\n  return typeof d === 'object' && d !== null && 'version' in d && Array.isArray((d as any).widgets);\n}","tryCatchPattern":"try {\n  await send('dashboard-import', data);\n} catch (e) {\n  if (e instanceof ValidationError && e.message.includes('dashboard.widgets')) {\n    console.error('Import file is not a valid dashboard export; re-export from Actual');\n  } else throw e;\n}","preventionTips":["Only import dashboard files produced by the app's export feature.","Run Array.isArray(parsed.widgets) as a pre-flight check.","Don't hand-edit exports in ways that can drop the widgets key.","Note version differences: old exports may need schema transformation."],"tags":["dashboard","validation","import","schema"],"backgroundTag":"schema-validation-failed","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}