flarum/framework · error · ValidationException
core.admin.appearance.custom_styles_cannot_use_less_features
Error message
core.admin.appearance.custom_styles_cannot_use_less_features
What it means
ValidateCustomLess::whenSettingsSaving throws ValidationException with the translated message core.admin.appearance.custom_styles_cannot_use_less_features when custom LESS/CSS settings contain constructs less.php cannot safely evaluate: @import directives (or the mistyped '@impor' which less.php parses the same way) or data-uri() calls. These features would let admins read arbitrary files at compile time, so they are blocked.
Solutions
- Remove any @import statements and data-uri() calls from the custom LESS/CSS.
- Load external stylesheets with <link> tags in custom HTML/header instead of CSS @import.
- Inline the imported LESS content directly, or add fonts via the site's HTML head section rather than LESS imports.
Example fix
// before (custom_less)
@import url("https://fonts.googleapis.com/css?family=Open+Sans");
// after (custom header HTML instead)
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans"> Defensive patterns
Strategy: validation
Validate before calling
// before saving custom styles
const blocked = /@impor|data-uri\s*\(/i;
if (typeof customLess === 'string' && blocked.test(customLess)) {
alert('Custom styles cannot use @import or data-uri()');
} Try / catch
try {
$this->settings->save($payload);
} catch (ValidationException $e) {
return response()->json(['errors' => $e->errors()], 422);
} Prevention
- Load external CSS with <link> tags in the header, never @import.
- Inline any needed LESS rather than importing files in custom styles.
- Remember '@impor' typo variants are also blocked by the same regex.
When it happens
Trigger: Saving admin Appearance settings where custom_less or custom_header contains '@import', '@impor', or 'data-uri(' (case-insensitive), detected by the regex in whenSettingsSaving before assets are compiled.
Common situations: Admins pasting CSS/LESS copied from themes that use @import for fonts or external stylesheets; importing Google Fonts via @import url(...) in custom styles.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- custom_less
- ValidationException (messages from password validator)
- validation. (translated message for )
- ValidationException (messages from validator)
- Importing " " is not allowed.
AI-assisted analysis of flarum/framework@4b939f6853 (2026-09-15).
Data as JSON: /api/errors/cddaa860c72597f0.
Report an issue: GitHub.
Appendix: source
Thrown at framework/core/src/Forum/ValidateCustomLess.php:70
isset($event->settings['custom_less']) ? ['custom_less'] : [],
array_intersect(
array_keys($event->settings),
array_column($this->customLessSettings, 'key')
)
);
foreach ($lessFeatureKeys as $key) {
// The file system is taken away from the compiler by
// LessCompiler::containImports(), which is what actually stops a
// custom-LESS file read. This check stays so the administrator is
// told at save time rather than silently getting a stylesheet with
// the import dropped. `@impor` is matched as well as `@import`,
// because less.php matches the directive as `@import?` and so
// parses both the same way.
if (is_string($event->settings[$key]) && preg_match('/@impor|data-uri\s*\(/i', $event->settings[$key])) {
$translator = $this->container->make(TranslatorInterface::class);
throw new ValidationException([
$key => $translator->trans('core.admin.appearance.custom_styles_cannot_use_less_features')
]);
}
}
// We haven't saved the settings yet, but we want to trial a full
// recompile of the CSS to see if this custom LESS will break
// anything. In order to do that, we will temporarily override the
// settings repository with the new settings so that the recompile
// is effective. We will also use a dummy filesystem so that nothing
// is actually written yet.
$settings = $this->container->make(SettingsRepositoryInterface::class);
$this->container->extend(
SettingsRepositoryInterface::class,
function ($settings) use ($event) {
return new OverrideSettingsRepository($settings, $event->settings);View on GitHub (pinned to 4b939f6853)