{"record":{"id":"4ada5277211884a3","repo":"actualbudget/actual","slug":"invalid-widget-idx-width-data-type-for-value","errorCode":null,"errorMessage":"Invalid widget.${idx}.width data-type for value ${widget.width}.","messagePattern":"Invalid widget\\.(.+?)\\.width data-type for value (.+?)\\.","errorType":"validation","errorClass":"ValidationError","httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/server/dashboard/app.ts","lineNumber":84,"sourceCode":"        '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        );\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)) {","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/dashboard/app.ts#L66-L102","documentation":"Each widget's width (grid column span) must be an integer. The dashboard import validator throws this ValidationError when widget.width is a float, string, null, or undefined, since spans must map to whole grid columns.","triggerScenarios":"Importing dashboard JSON where a widget's width is 1.5, \"2\", null, or absent; exports generated from percentage-based sizing math.","commonSituations":"Responsive layout generators dividing available width; spreadsheet edits turning numbers into strings; hand-written widget definitions missing width.","solutions":["Set widget.width = Math.round(widget.width) before import.","Give every widget an explicit integer width (typically 1–4 grid columns).","Convert string values with Number() and check Number.isInteger.","Fix the generator to emit integer spans.","Re-export from the app to obtain valid widths."],"exampleFix":"// before\nwidth: Math.floor(cols / widgets.length)\n// after (guaranteed integer, >= 1)\nwidth: Math.max(1, Math.round(cols / widgets.length))","handlingStrategy":"validation","validationCode":"widgets.forEach((w, i) => {\n  if (!Number.isInteger(w.width)) throw new Error(`Widget #${i}: width must be an integer, got ${w.width}`);\n});","typeGuard":"function hasIntegerWidth(w: { width: unknown }): w is { width: number } {\n  return Number.isInteger(w.width);\n}","tryCatchPattern":"try {\n  await send('dashboard-import', { version: 1, widgets });\n} catch (e) {\n  if (e instanceof ValidationError && e.message.includes('.width data-type')) {\n    console.error('Non-integer width in import; round spans and retry');\n  } else throw e;\n}","preventionTips":["Use Math.max(1, Math.round(span)) when deriving widths from ratios.","Validate all geometry fields (x, y, width, height) together.","Avoid spreadsheet-based JSON editing that produces string numerics.","Prefer whole grid-column constants (1–4) in generated layouts."],"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"}