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

  1. Set a concrete default site locale/language in Halo system settings so every request resolves a non-empty language.
  2. Verify any custom LocaleResolver never returns Locale.ROOT for theme rendering.
  3. Send a valid Accept-Language header from the client, or rely on the configured default.
  4. 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

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


AI-assisted analysis of halo-dev/halo@d2f5165f9c (2026-08-14). Data as JSON: /api/errors/0e8379dba721e259. Report an issue: GitHub.