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
- Fix the theme CSS: give the variable a value, e.g. `--font-ui: Georgia, serif;`.
- Include at least one generic family fallback (serif, sans-serif, monospace).
- 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
- Always end font stacks with a generic family (serif, sans-serif, monospace).
- Lint theme CSS for empty declarations before publishing.
- Never leave --font-* variables blank in templates.
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
- Invalid font-family value for "${property}": empty font name
- Invalid font-family value for "${property}": function calls
- Invalid value "${trimmedValue}" for property "${property}".
- Theme CSS contains nested blocks or additional selectors. On
- Invalid font src: only data: URIs are allowed in @font-face.
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/98e807fd763d2b36.
Report an issue: GitHub.