actualbudget/actual · error
Invalid property "${property}". Only CSS custom properties (
Error message
Invalid property "${property}". Only CSS custom properties (starting with --) are allowed. What it means
Only CSS custom properties (variables) are permitted inside the :root block of a custom theme. validateRootContent splits declarations and rejects any whose property name does not begin with the '--' prefix. This restricts themes to variable overrides so arbitrary CSS rules cannot be injected.
Source
Thrown at packages/desktop-client/src/style/customThemes.ts:372
// Check for nested blocks
if (/\{/.test(rootContent)) {
throw new Error(
'Theme CSS contains nested blocks or additional selectors. Only CSS variable declarations are allowed inside :root { ... }.',
);
}
for (const decl of splitDeclarations(rootContent)) {
const colonIndex = decl.indexOf(':');
if (colonIndex === -1) {
throw new Error(`Invalid CSS declaration: "${decl}"`);
}
const property = decl.substring(0, colonIndex).trim();
// Property must start with --
if (!property.startsWith('--')) {
throw new Error(
`Invalid property "${property}". Only CSS custom properties (starting with --) are allowed.`,
);
}
// Validate property name format
// CSS custom property names must:
// - Start with --
// - Not be empty (not just --)
// - Not end with a dash
// - Contain only valid characters (letters, digits, underscore, dash, but not at start/end positions)
if (property === '--' || property === '-') {
throw new Error(
`Invalid property "${property}". Property name cannot be empty or contain only dashes.`,
);
}
// Check for invalid characters in property name (no brackets, spaces, special chars except dash/underscore)
// Property name after -- should only contain: letters, digits, underscore, and dashes (not consecutive dashes at start/end)View on GitHub (pinned to d4334cb6e6)
Solutions
- Prefix the property with '--' if it was intended as a variable, or rename it to a custom property
- Remove all regular CSS properties from :root; only --variable declarations are allowed
- Move global styling needs out of the theme CSS field — it is not supported by design
- Pre-validate: split on ';' and assert every chunk starts with '--'
Example fix
// before
:root {
color: red;
}
// after
:root {
--color-text: red;
} Defensive patterns
Strategy: validation
Validate before calling
function onlyCustomProperties(css: string): boolean {
const root = css.match(/:root\s*\{([\s\S]*?)\}/);
if (!root) return false;
return root[1]
.split(';')
.map((d) => d.trim())
.filter(Boolean)
.every((d) => d.split(':')[0].trim().startsWith('--'));
} Type guard
const isCustomPropertyDecl = (decl: string): boolean =>
decl.includes(':') && decl.split(':')[0].trim().startsWith('--'); Try / catch
try {
const validated = validateThemeCss(userCss);
} catch (e) {
if (e instanceof Error && e.message.includes('Only CSS custom properties')) {
showError('Theme CSS may only contain --variable declarations inside :root.');
}
} Prevention
- Never paste regular CSS rules into the theme field
- Educate users that themes are variable overrides only
- Pre-process pasted CSS to extract only --variable lines
- Add editor hints/placeholders showing only --variable syntax
When it happens
Trigger: Calling validateThemeCss with a :root block containing a regular CSS property such as 'color: red;', 'margin: 0;', or a selector-like token before the colon, e.g. ':root { color: red; --a: b; }'.
Common situations: Pasting a full CSS stylesheet into the custom theme editor instead of just variable overrides, copying rules from a theme that supported full CSS, or misunderstanding that the theme field takes variables only.
Related errors
- Invalid CSS declaration: "${decl}"
- Invalid property "${property}". Property name cannot be empt
- Invalid property "${property}". Property name cannot be empt
- Invalid property "${property}". Property name contains inval
- Invalid property "${property}". Property name cannot end wit
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/5d545a4f1a45e253.
Report an issue: GitHub.