halo-dev/halo · error · IllegalArgumentException

Unsupported file category matcher for name: {}

Error message

Unsupported file category matcher for name: {}

What it means

FileCategoryMatcher.of(String) is a public factory in the api/ library that resolves a category name to one of the enum constants ALL, IMAGE, SVG, AUDIO, VIDEO, ARCHIVE, DOCUMENT (matched case-insensitively). It throws IllegalArgumentException when no constant name matches the supplied string. Because the lookup is name-based, callers must pass one of the seven documented category names exactly (modulo case).

Source

Thrown at api/src/main/java/run/halo/app/infra/FileCategoryMatcher.java:103

                "application/vnd.oasis.opendocument.spreadsheet",
                "application/vnd.oasis.opendocument.presentation");

        @Override
        public boolean match(String mimeType) {
            return DOCUMENT_MIME_TYPES.contains(mimeType);
        }
    };

    public abstract boolean match(String mimeType);

    /** Get the file category matcher by name. */
    public static FileCategoryMatcher of(String name) {
        for (var matcher : values()) {
            if (matcher.name().equalsIgnoreCase(name)) {
                return matcher;
            }
        }
        throw new IllegalArgumentException("Unsupported file category matcher for name: " + name);
    }
}

View on GitHub (pinned to d2f5165f9c)

Solutions

  1. Pass one of the exact enum names: ALL, IMAGE, SVG, AUDIO, VIDEO, ARCHIVE, DOCUMENT.
  2. If you take user input, validate it against FileCategoryMatcher.values() (or Arrays.stream(...).map(Enum::name)) before calling of().
  3. Catch IllegalArgumentException and fall back to ALL or a sensible default category.
  4. If a new alias is needed, add it as a real enum constant — of() only matches constant names, never aliases.

Example fix

// before
var matcher = FileCategoryMatcher.of(userInput); // throws if userInput is "img"

// after
var matcher = Arrays.stream(FileCategoryMatcher.values())
    .filter(m -> m.name().equalsIgnoreCase(userInput))
    .findFirst()
    .orElse(FileCategoryMatcher.ALL);
Defensive patterns

Strategy: validation

Validate before calling

static final Set<String> VALID =
    Arrays.stream(FileCategoryMatcher.values())
          .map(Enum::name)
          .map(String::toLowerCase)
          .collect(Collectors.toSet());

if (name == null || !VALID.contains(name.toLowerCase(Locale.ROOT))) {
    // log and use a safe default instead of calling of()
    return FileCategoryMatcher.ALL;
}

Type guard

static boolean isKnownCategory(String name) {
    if (name == null) return false;
    return Arrays.stream(FileCategoryMatcher.values())
        .anyMatch(m -> m.name().equalsIgnoreCase(name));
}

Try / catch

try {
    var matcher = FileCategoryMatcher.of(name);
} catch (IllegalArgumentException e) {
    log.warn("Unknown file category [{}], falling back to ALL", name);
    matcher = FileCategoryMatcher.ALL;
}

Prevention

When it happens

Trigger: Calling FileCategoryMatcher.of("images"), of("img"), of(""), of(null) (NPE on equalsIgnoreCase), or of("TEXT") — none of which equal a constant name. A plugin or theme reading a free-text category field and forwarding it unvalidated.

Common situations: Migrating from an older API that accepted different category labels; passing a MIME-type string (e.g. "image/png") instead of a category name; frontend sends a localized or aliased category token that the backend enum does not know.

Related errors


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