actualbudget/actual · error · ValidationError

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

Error message

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

What it means

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.

Source

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

      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)) {
        reportModel.validate(widget.meta);
      }
    });
  },
};

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Set widget.height = Math.round(widget.height) before import.
  2. Add an explicit integer height to every widget.
  3. Coerce strings with Number() and validate with Number.isInteger.
  4. Fix the generating code to round heights to whole rows.
  5. Re-export from the app for a valid schema baseline.

Example fix

// before
height: chartHeight / 100
// after
height: Math.max(1, Math.round(chartHeight / 100))
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

function hasIntegerHeight(w: { height: unknown }): w is { height: number } {
  return Number.isInteger(w.height);
}

Try / catch

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

Prevention

When it happens

Trigger: Importing dashboard JSON where a widget's height is 0.5, "1", null, or the field is absent; generators computing heights from ratios.

Common situations: Chart-height calculators emitting floats; exports trimmed by hand missing height; third-party tooling producing incomplete widget objects.

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/aff5b3bac9fad85d. Report an issue: GitHub.