actualbudget/actual · error · ValidationError
Invalid dashboard.widgets data type: it must be an array of
Error message
Invalid dashboard.widgets data type: it must be an array of widgets.
What it means
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.
Source
Thrown at packages/loot-core/src/server/dashboard/app.ts:57
'budget-analysis-card',
'markdown-card',
'summary-card',
'calendar-card',
'formula-card',
'custom-report',
'sankey-card',
'balance-forecast-card',
'age-of-money-card',
'monte-carlo-card',
].includes(type);
}
const exportModel = {
validate(dashboard: ExportImportDashboard) {
requiredFields('Dashboard', dashboard, ['version', 'widgets']);
if (!Array.isArray(dashboard.widgets)) {
throw new ValidationError(
'Invalid dashboard.widgets data type: it must be an array of widgets.',
);
}
dashboard.widgets.forEach((widget, idx) => {
requiredFields(`Dashboard widget #${idx}`, widget, [
'type',
'x',
'y',
'width',
'height',
...(isExportedCustomReportWidget(widget) ? ['meta' as const] : []),
]);
if (!Number.isInteger(widget.x)) {
throw new ValidationError(
`Invalid widget.${idx}.x data-type for value ${widget.x}.`,
);View on GitHub (pinned to d4334cb6e6)
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.
Example fix
// before
const data = JSON.parse(text);
await send('dashboard-import', data); // data.widgets is an object
// after
const data = JSON.parse(text);
if (!Array.isArray(data.widgets)) {
data.widgets = data.widgets ? [data.widgets] : [];
}
await send('dashboard-import', data); Defensive patterns
Strategy: validation
Validate before calling
const data = JSON.parse(text);
if (!data || typeof data !== 'object' || !Array.isArray(data.widgets)) {
throw new Error('Dashboard import file must contain a widgets array');
} Type guard
function isDashboardImport(d: unknown): d is { version: number; widgets: unknown[] } {
return typeof d === 'object' && d !== null && 'version' in d && Array.isArray((d as any).widgets);
} Try / catch
try {
await send('dashboard-import', data);
} catch (e) {
if (e instanceof ValidationError && e.message.includes('dashboard.widgets')) {
console.error('Import file is not a valid dashboard export; re-export from Actual');
} else throw e;
} Prevention
- 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.
When it happens
Trigger: 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).
Common situations: Hand-edited dashboard export losing the widgets field; exporting one widget and importing the widget object directly; JSON schema drift between Actual versions.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Invalid widget.${idx}.x data-type for value ${widget.x}.
- Invalid widget.${idx}.y data-type for value ${widget.y}.
- Invalid widget.${idx}.width data-type for value ${widget.wid
- Invalid widget.${idx}.height data-type for value ${widget.he
- Invalid widget.${idx}.type value ${String(widget.type)}.
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/435e54555ded6d21.
Report an issue: GitHub.