halo-dev/halo · warning · IllegalArgumentException

Locale "{locale}" cannot be used as it does not specify a la

Error message

Locale "{locale}" cannot be used as it does not specify a language.

What it means

Thrown as IllegalArgumentException by LanguageUtils.computeLangFromLocale when the Locale has a blank language tag. The method builds resource-name candidates (_lang, _lang_COUNTRY, ...) and needs at least the language component to proceed.

Source

Thrown at application/src/main/java/run/halo/app/notification/LanguageUtils.java:29

 *
 * @author guqing
 * @since 2.10.0
 */
@UtilityClass
public class LanguageUtils {

    /**
     * Compute all the possible languages we should use: *_gl_ES-gheada, *_gl_ES, _gl... from a given locale. The first
     * element of the list is "default" if it can not find the language, use default.
     *
     * @param locale locale
     * @return list of possible languages, from less specific to more specific.
     */
    public static List<String> computeLangFromLocale(Locale locale) {
        final List<String> resourceNames = new ArrayList<>(5);

        if (StringUtils.isBlank(locale.getLanguage())) {
            throw new IllegalArgumentException(
                    "Locale \"" + locale + "\" " + "cannot be used as it does not specify a language.");
        }

        resourceNames.add("default");
        resourceNames.add(locale.getLanguage());

        if (StringUtils.isNotBlank(locale.getCountry())) {
            resourceNames.add(locale.getLanguage() + "_" + locale.getCountry());
        }

        if (StringUtils.isNotBlank(locale.getVariant())) {
            resourceNames.add(locale.getLanguage() + "_" + locale.getCountry() + "-" + locale.getVariant());
        }
        return resourceNames;
    }
}

View on GitHub (pinned to d2f5165f9c)

Solutions

  1. Fall back to a default Locale (e.g. Locale.ENGLISH or the system default) when the language is blank before calling computeLangFromLocale.
  2. Validate the Accept-Language/locale input and reject/normalize blank languages upstream.
  3. Use Locale.forLanguageTag with a checked, well-formed tag.

Example fix

// before
List<String> langs = LanguageUtils.computeLangFromLocale(locale);

// after
Locale safe = StringUtils.isBlank(locale.getLanguage()) ? Locale.getDefault() : locale;
List<String> langs = LanguageUtils.computeLangFromLocale(safe);
Defensive patterns

Strategy: validation

Validate before calling

Locale safe = (locale == null || StringUtils.isBlank(locale.getLanguage()))
    ? Locale.getDefault() : locale;
List<String> langs = LanguageUtils.computeLangFromLocale(safe);

Type guard

static boolean localeHasLanguage(Locale l) {
    return l != null && StringUtils.isNotBlank(l.getLanguage());
}

Try / catch

try {
    LanguageUtils.computeLangFromLocale(locale);
} catch (IllegalArgumentException e) {
    // fall back to default language bundle
    LanguageUtils.computeLangFromLocale(Locale.getDefault());
}

Prevention

When it happens

Trigger: Calling computeLangFromLocale with a Locale whose getLanguage() is empty, e.g. new Locale("") or a Locale built from a country-only/variant-only string, or Locale.ROOT.

Common situations: Parsing an Accept-Language header that yields an empty language; defaulting to Locale.ROOT accidentally; constructing Locale from malformed input; a notification/template resolver receiving a blank locale.

Related errors


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