halo-dev/halo · error · IllegalArgumentException

No such thumbnail size: {}

Error message

No such thumbnail size: {}

What it means

Thrown by ThumbnailSize.fromName when the supplied name does not case-insensitively match any of the enum constants S, M, L, XL. fromName performs an exact (case-insensitive) name lookup and has no fallback, unlike fromWidth (which defaults to M). Callers passing an arbitrary user-supplied size string will trigger this IllegalArgumentException.

Source

Thrown at api/src/main/java/run/halo/app/core/attachment/ThumbnailSize.java:41

     * @param width width string
     */
    public static ThumbnailSize fromWidth(String width) {
        for (ThumbnailSize value : values()) {
            if (String.valueOf(value.getWidth()).equals(width)) {
                return value;
            }
        }
        return ThumbnailSize.M;
    }

    /** Convert name to {@link ThumbnailSize}. */
    public static ThumbnailSize fromName(String name) {
        for (ThumbnailSize value : values()) {
            if (value.name().equalsIgnoreCase(name)) {
                return value;
            }
        }
        throw new IllegalArgumentException("No such thumbnail size: " + name);
    }

    public static Optional<ThumbnailSize> optionalValueOf(String name) {
        for (ThumbnailSize value : values()) {
            if (value.name().equalsIgnoreCase(name)) {
                return Optional.of(value);
            }
        }
        return Optional.empty();
    }

    public static Integer[] allowedWidths() {
        return Arrays.stream(ThumbnailSize.values())
                .map(ThumbnailSize::getWidth)
                .toArray(Integer[]::new);
    }
}

View on GitHub (pinned to d2f5165f9c)

Solutions

  1. Call ThumbnailSize.optionalValueOf(name) and handle the empty Optional (default or reject) instead of fromName for untrusted input.
  2. Validate the input against the allowed set {S, M, L, XL} (case-insensitive) before calling fromName.
  3. Map numeric widths via fromWidth if the caller has a pixel width rather than a name.

Example fix

// before
ThumbnailSize size = ThumbnailSize.fromName(userInput);

// after
ThumbnailSize size = ThumbnailSize.optionalValueOf(userInput)
    .orElse(ThumbnailSize.M);
Defensive patterns

Strategy: validation

Validate before calling

ThumbnailSize size = ThumbnailSize.optionalValueOf(name)
    .orElseThrow(() -> new IllegalArgumentException("Invalid thumbnail size: " + name));
// or default: .orElse(ThumbnailSize.M);

Type guard

boolean valid = Arrays.stream(ThumbnailSize.values())
    .anyMatch(v -> v.name().equalsIgnoreCase(name));

Try / catch

try {
    ThumbnailSize size = ThumbnailSize.fromName(input);
} catch (IllegalArgumentException e) {
    size = ThumbnailSize.M; // graceful fallback for untrusted input
}

Prevention

When it happens

Trigger: ThumbnailSize.fromName("medium"), fromName("800"), fromName(""), fromName(null-via-string), or any value not equal to s/m/l/xl (case-insensitive).

Common situations: REST/config input that accepts a free-text size; migrating from width-based ('800') to name-based API; a typo like 'md' or 'large-xl'; locale-specific aliases.

Related errors


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