{"record":{"id":"aff5b3bac9fad85d","repo":"actualbudget/actual","slug":"invalid-widget-idx-height-data-type-for-value","errorCode":null,"errorMessage":"Invalid widget.${idx}.height data-type for value ${widget.height}.","messagePattern":"Invalid widget\\.(.+?)\\.height data-type for value (.+?)\\.","errorType":"validation","errorClass":"ValidationError","httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/server/dashboard/app.ts","lineNumber":90,"sourceCode":"      if (!Number.isInteger(widget.x)) {\n        throw new ValidationError(\n          `Invalid widget.${idx}.x data-type for value ${widget.x}.`,\n        );\n      }\n\n      if (!Number.isInteger(widget.y)) {\n        throw new ValidationError(\n          `Invalid widget.${idx}.y data-type for value ${widget.y}.`,\n        );\n      }\n\n      if (!Number.isInteger(widget.width)) {\n        throw new ValidationError(\n          `Invalid widget.${idx}.width data-type for value ${widget.width}.`,\n        );\n      }\n\n      if (!Number.isInteger(widget.height)) {\n        throw new ValidationError(\n          `Invalid widget.${idx}.height data-type for value ${widget.height}.`,\n        );\n      }\n\n      if (!isWidgetType(widget.type)) {\n        throw new ValidationError(\n          `Invalid widget.${idx}.type value ${String(widget.type)}.`,\n        );\n      }\n\n      if (isExportedCustomReportWidget(widget)) {\n        reportModel.validate(widget.meta);\n      }\n    });\n  },\n};\n","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/dashboard/app.ts#L72-L108","documentation":"Each widget's height (grid row span) must be an integer. The dashboard import validator throws this ValidationError when widget.height is fractional, a string, null, or missing, as the grid layout cannot place partial-row widgets.","triggerScenarios":"Importing dashboard JSON where a widget's height is 0.5, \"1\", null, or the field is absent; generators computing heights from ratios.","commonSituations":"Chart-height calculators emitting floats; exports trimmed by hand missing height; third-party tooling producing incomplete widget objects.","solutions":["Set widget.height = Math.round(widget.height) before import.","Add an explicit integer height to every widget.","Coerce strings with Number() and validate with Number.isInteger.","Fix the generating code to round heights to whole rows.","Re-export from the app for a valid schema baseline."],"exampleFix":"// before\nheight: chartHeight / 100\n// after\nheight: Math.max(1, Math.round(chartHeight / 100))","handlingStrategy":"validation","validationCode":"widgets.forEach((w, i) => {\n  if (!Number.isInteger(w.height)) throw new Error(`Widget #${i}: height must be an integer, got ${w.height}`);\n});","typeGuard":"function hasIntegerHeight(w: { height: unknown }): w is { height: number } {\n  return Number.isInteger(w.height);\n}","tryCatchPattern":"try {\n  await send('dashboard-import', { version: 1, widgets });\n} catch (e) {\n  if (e instanceof ValidationError && e.message.includes('.height data-type')) {\n    console.error('Non-integer height in import; round row spans and retry');\n  } else throw e;\n}","preventionTips":["Round computed chart heights to whole rows with Math.round.","Give every widget an explicit integer height in generated exports.","Validate geometry as a group before calling the import handler.","Re-export a known-good dashboard and diff against your generated file."],"tags":["dashboard","validation","import","types"],"backgroundTag":"schema-validation-failed","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}