actualbudget/actual · error · ValidationError

Invalid widget.${idx}.width data-type for value ${widget.wid

Error message

Invalid widget.${idx}.width data-type for value ${widget.width}.

What it means

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.

Source

Thrown at packages/loot-core/src/server/dashboard/app.ts:84

        '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}.`,
        );
      }

      if (!Number.isInteger(widget.y)) {
        throw new ValidationError(
          `Invalid widget.${idx}.y data-type for value ${widget.y}.`,
        );
      }

      if (!Number.isInteger(widget.width)) {
        throw new ValidationError(
          `Invalid widget.${idx}.width data-type for value ${widget.width}.`,
        );
      }

      if (!Number.isInteger(widget.height)) {
        throw new ValidationError(
          `Invalid widget.${idx}.height data-type for value ${widget.height}.`,
        );
      }

      if (!isWidgetType(widget.type)) {
        throw new ValidationError(
          `Invalid widget.${idx}.type value ${String(widget.type)}.`,
        );
      }

      if (isExportedCustomReportWidget(widget)) {

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Set widget.width = Math.round(widget.width) before import.
  2. Give every widget an explicit integer width (typically 1–4 grid columns).
  3. Convert string values with Number() and check Number.isInteger.
  4. Fix the generator to emit integer spans.
  5. Re-export from the app to obtain valid widths.

Example fix

// before
width: Math.floor(cols / widgets.length)
// after (guaranteed integer, >= 1)
width: Math.max(1, Math.round(cols / widgets.length))
Defensive patterns

Strategy: validation

Validate before calling

widgets.forEach((w, i) => {
  if (!Number.isInteger(w.width)) throw new Error(`Widget #${i}: width must be an integer, got ${w.width}`);
});

Type guard

function hasIntegerWidth(w: { width: unknown }): w is { width: number } {
  return Number.isInteger(w.width);
}

Try / catch

try {
  await send('dashboard-import', { version: 1, widgets });
} catch (e) {
  if (e instanceof ValidationError && e.message.includes('.width data-type')) {
    console.error('Non-integer width in import; round spans and retry');
  } else throw e;
}

Prevention

When it happens

Trigger: Importing dashboard JSON where a widget's width is 1.5, "2", null, or absent; exports generated from percentage-based sizing math.

Common situations: Responsive layout generators dividing available width; spreadsheet edits turning numbers into strings; hand-written widget definitions missing width.

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


AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29). Data as JSON: /api/errors/4ada5277211884a3. Report an issue: GitHub.