actualbudget/actual · error

Invalid font-family value for "${property}": value must not

Error message

Invalid font-family value for "${property}": value must not be empty.

What it means

validateFontFamilyValue checks every --font-* CSS variable value in a custom theme before it is installed. It throws this error when the entire font-family value is empty or whitespace-only. Font stacks must name at least one font (quoted or unquoted); an empty value would produce invalid CSS.

Source

Thrown at packages/desktop-client/src/style/customThemes.ts:115

 * Validate a font-family value for a --font-* CSS variable.
 *
 * Any font name is allowed — referencing a font the user doesn't have
 * installed simply triggers the browser's normal fallback behaviour
 * (no network requests). The only things we block are function calls
 * (url(), expression(), etc.) because those could load external resources
 * or execute expressions.
 *
 * Quoted or unquoted font names are both accepted.
 *
 * Examples of accepted values:
 *   Georgia, serif
 *   'Fira Code', monospace
 *   "My Theme Font", sans-serif
 */
function validateFontFamilyValue(value: string, property: string): void {
  const trimmed = value.trim();
  if (!trimmed) {
    throw new Error(
      `Invalid font-family value for "${property}": value must not be empty.`,
    );
  }

  // Split on commas, then validate each font name
  const families = trimmed.split(',');

  for (const raw of families) {
    const name = stripQuotes(raw);

    if (!name) {
      throw new Error(
        `Invalid font-family value for "${property}": empty font name in comma-separated list.`,
      );
    }

    // Reject anything that looks like a function call (url(), expression(), etc.)
    if (/\(/.test(name)) {

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Fix the theme CSS: give the variable a value, e.g. `--font-ui: Georgia, serif;`.
  2. Include at least one generic family fallback (serif, sans-serif, monospace).
  3. Reinstall the theme after fixing the source actual.css.

Example fix

// before (in actual.css)
--font-ui: ;
// after
--font-ui: 'Inter', sans-serif;
Defensive patterns

Strategy: validation

Validate before calling

function isValidFontValue(v) {
  return typeof v === 'string' && v.trim().length > 0;
}
if (!isValidFontValue(rawDecl.value)) throw new Error('font value required');

Type guard

function isNonEmptyString(v: unknown): v is string {
  return typeof v === 'string' && v.trim() !== '';
}

Try / catch

try {
  await installTheme(css);
} catch (err) {
  if ((err as Error).message.includes('value must not be empty')) {
    // show which --font-* variable is blank in the theme editor
  } else throw err;
}

Prevention

When it happens

Trigger: A theme's actual.css contains a declaration like `--font-ui: ;` or `--font-mono: ;` inside :root, which is passed through validatePropertyValue -> validateFontFamilyValue during validateThemeCss.

Common situations: Theme author left a font variable blank in their CSS template; a generator or minifier stripped the value; manual editing of actual.css accidentally deleted the font list.

Related errors


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