{"record":{"id":"1dc818bad3a10091","repo":"actualbudget/actual","slug":"validation-error","errorCode":"validation-error","errorMessage":"err.message (rethrown ValidationError message)","messagePattern":"err\\.message \\(rethrown ValidationError message\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/server/dashboard/app.ts","lineNumber":347,"sourceCode":"                ]),\n              ),\n              tombstone: false,\n            }),\n          ),\n      ]);\n    });\n\n    return { status: 'ok' as const };\n  } catch (err: unknown) {\n    if (err instanceof Error) {\n      err.message = 'Error importing file: ' + err.message;\n      captureException(err);\n    }\n    if (err instanceof SyntaxError) {\n      throw new Error('Invalid JSON file.', { cause: 'json-parse-error' });\n    }\n    if (err instanceof ValidationError) {\n      throw new Error(err.message, { cause: 'validation-error' });\n    }\n    throw new Error('Internal error occurred during import.', {\n      cause: 'internal-error',\n    });\n  }\n}\n\nexport type DashboardHandlers = {\n  'dashboard-create': typeof createDashboardPage;\n  'dashboard-delete': typeof deleteDashboardPage;\n  'dashboard-rename': typeof renameDashboardPage;\n  'dashboard-update': typeof updateDashboard;\n  'dashboard-update-widget': typeof updateDashboardWidget;\n  'dashboard-reset': typeof resetDashboard;\n  'dashboard-add-widget': typeof addDashboardWidget;\n  'dashboard-remove-widget': typeof removeDashboardWidget;\n  'dashboard-copy-widget': typeof copyDashboardWidget;\n  'dashboard-import': typeof importDashboard;","sourceCodeStart":329,"sourceCodeEnd":365,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/dashboard/app.ts#L329-L365","documentation":"If exportModel.validate() raises a ValidationError while parsing the imported dashboard (missing fields, wrong data types, unknown widget types), importDashboard rethrows the original message as `Error(err.message, { cause: 'validation-error' })`. The message is the specific validation failure (e.g. \"Invalid widget.0.type value ...\").","triggerScenarios":"Importing a dashboard JSON whose structure violates the ExportImportDashboard schema: missing version/widgets, non-integer x/y/width/height, unknown widget type, missing meta on custom-report widgets, or invalid report meta.","commonSituations":"Schema drift between Actual versions; hand-edited export files; exports from third-party tooling that guesses the format.","solutions":["Read the rethrown message — it names the exact field and index that failed; fix that field in the JSON.","Compare the file against a freshly exported dashboard from the same Actual version and align the schema.","Ensure required fields (version, widgets, per-widget type/x/y/width/height, meta for custom-report) are present and correctly typed."],"exampleFix":"// before\n{ \"widgets\": [{ \"type\": \"net-worth-card\", \"x\": \"0\", \"y\": 0, \"width\": 1, \"height\": 1 }] }\n// after\n{ \"version\": 1, \"widgets\": [{ \"type\": \"net-worth-card\", \"x\": 0, \"y\": 0, \"width\": 1, \"height\": 1 }] }","handlingStrategy":"validation","validationCode":"const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));\nif (typeof data.version !== 'number' || !Array.isArray(data.widgets)) {\n  throw new Error('Dashboard file must have numeric version and widgets array');\n}\ndata.widgets.forEach((w, i) => {\n  for (const f of ['type','x','y','width','height']) {\n    if (w[f] === undefined) throw new Error(`widgets[${i}] missing ${f}`);\n  }\n  for (const f of ['x','y','width','height']) {\n    if (!Number.isInteger(w[f])) throw new Error(`widgets[${i}].${f} must be an integer`);\n  }\n});","typeGuard":"function isDashboardExport(v: unknown): v is ExportImportDashboard {\n  return (\n    typeof v === 'object' && v !== null &&\n    typeof (v as any).version === 'number' &&\n    Array.isArray((v as any).widgets) &&\n    (v as any).widgets.every((w: any) =>\n      typeof w.type === 'string' &&\n      Number.isInteger(w.x) && Number.isInteger(w.y) &&\n      Number.isInteger(w.width) && Number.isInteger(w.height))\n  );\n}","tryCatchPattern":"try {\n  await send('dashboard-import', { filePath, dashboardPageId });\n} catch (e) {\n  if (e.cause === 'validation-error') {\n    console.error(`Schema problem in import file: ${e.message}`);\n  }\n}","preventionTips":["Validate the export against the schema before importing.","Keep export files unmodified between export and import.","Match export/import versions of Actual to avoid schema drift."],"tags":["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"}