halo-dev/halo · error · TemplateProcessingException
Locale "{}" cannot be used as it does not specify a language
Error message
Locale "{}" cannot be used as it does not specify a language. What it means
ThemeMessageResolutionUtils.computeMessageResourceNamesFromBase() builds the i18n resource name list for a theme and requires the Locale to carry a language. If locale.getLanguage() is empty/blank, a TemplateProcessingException is thrown because there is no base language to resolve message files (messages_<language>.properties) against. Thymeleaf rethrows this during theme rendering.
Source
Thrown at application/src/main/java/run/halo/app/theme/message/ThemeMessageResolutionUtils.java:94
} catch (final IOException ignored) {
// File might not exist, simply try the next one
}
}
if (combinedMessages == null) {
return EMPTY_MESSAGES;
}
return Collections.unmodifiableMap(combinedMessages);
}
private static List<String> computeMessageResourceNamesFromBase(final Locale locale) {
final List<String> resourceNames = new ArrayList<>(5);
if (StringUtils.isEmptyOrWhitespace(locale.getLanguage())) {
throw new TemplateProcessingException(
"Locale \"" + locale + "\" " + "cannot be used as it does not specify a language.");
}
resourceNames.add(getResourceName("default"));
resourceNames.add(getResourceName(locale.getLanguage()));
if (!StringUtils.isEmptyOrWhitespace(locale.getCountry())) {
resourceNames.add(getResourceName(locale.getLanguage() + "_" + locale.getCountry()));
}
if (!StringUtils.isEmptyOrWhitespace(locale.getVariant())) {
resourceNames.add(
getResourceName(locale.getLanguage() + "_" + locale.getCountry() + "-" + locale.getVariant()));
}
return resourceNames;
}
View on GitHub (pinned to d2f5165f9c)
Solutions
- Set a concrete default site locale/language in Halo system settings so every request resolves a non-empty language.
- Verify any custom LocaleResolver never returns Locale.ROOT for theme rendering.
- Send a valid Accept-Language header from the client, or rely on the configured default.
- If migrating, re-populate the locale setting before exposing the site.
Example fix
// before: resolver can return Locale.ROOT
// Locale locale = resolver.resolveLocale(request); // may be ROOT
// after: guarantee a language
// Locale locale = resolver.resolveLocale(request);
// if (locale == null || locale.getLanguage().isBlank()) {
// locale = Locale.getDefault();
// } Defensive patterns
Strategy: validation
Validate before calling
// Before rendering a theme, ensure the Locale has a language:
Locale locale = localeResolver.resolveLocale(exchange.getRequest());
if (locale == null || locale.getLanguage() == null || locale.getLanguage().isBlank()) {
locale = Locale.getDefault(); // or a configured fallback
} Type guard
// Java guard
static boolean hasLanguage(Locale l) {
return l != null && !l.getLanguage().isBlank();
} Try / catch
try {
renderTheme(model, locale);
} catch (TemplateProcessingException e) {
if (e.getMessage().contains("does not specify a language")) {
renderTheme(model, Locale.getDefault()); // fallback locale
} else throw e;
} Prevention
- Always configure a concrete default site locale in system settings.
- Ensure any custom LocaleResolver never returns Locale.ROOT for theme pages.
- Send a valid Accept-Language header from clients.
- Add a test rendering a theme with the default locale to catch regressions.
When it happens
Trigger: Rendering a theme page when the resolved Locale (from site settings, Accept-Language, or a controller) is Locale.ROOT or otherwise has no language component. computeMessageResourceNamesFromBase is called while resolving theme message bundles for the current request locale.
Common situations: Site default locale misconfigured to an empty/blank value; a client sending an Accept-Language that resolves to a language-less Locale; a custom LocaleResolver returning Locale.ROOT; migration that wiped the locale setting.
Related errors
- Exception loading messages file
- Locale "{locale}" cannot be used as it does not specify a la
- validation.error.email.pattern
- validation.error.password.size
- problemDetail.comment.turnedOff
AI-assisted analysis of halo-dev/halo@d2f5165f9c (2026-08-14).
Data as JSON: /api/errors/0e8379dba721e259.
Report an issue: GitHub.