halo-dev/halo · warning · IllegalArgumentException
Page number must be a number
Error message
Page number must be a number
What it means
PageUrlUtils.parseInt is used by the theme router's toNextPage/toPrevPage helpers to derive adjacent page numbers from the current page string. It throws IllegalArgumentException when NumberUtils.isParsable(pageStr) is false, i.e. the value is not a numeric literal. This is part of building pagination URLs for theme page routes.
Source
Thrown at api/src/main/java/run/halo/app/theme/router/PageUrlUtils.java:104
return Objects.toString(path, "/");
}
private static String appendPagePart(String path, long page) {
return PathUtils.combinePath(path, PAGE_PART, String.valueOf(page));
}
private static String toNextPage(String pageStr, long total) {
long page = Math.min(parseInt(pageStr) + 1, Math.max(total, 1));
return String.valueOf(page);
}
private static int toPrevPage(String pageStr) {
return Math.max(parseInt(pageStr) - 1, 1);
}
private static int parseInt(String pageStr) {
if (!NumberUtils.isParsable(pageStr)) {
throw new IllegalArgumentException("Page number must be a number");
}
return NumberUtils.toInt(pageStr, 1);
}
}
View on GitHub (pinned to d2f5165f9c)
Solutions
- Correct the page segment in the URL to an integer (e.g. /page/2/).
- If you control permalink rules, ensure only \d+ can land in the page position.
- Return a 404 for non-numeric page paths at the routing layer instead of letting parseInt throw.
- Audit theme templates that construct next/prev links to always emit numeric page values.
Defensive patterns
Strategy: validation
Validate before calling
if (!NumberUtils.isParsable(pageStr)) {
// return 404 / default page 1 instead of calling toNextPage/toPrevPage
return 1;
} Type guard
static boolean isPageNumber(String s) {
return s != null && s.matches("\\d+") && Integer.parseInt(s) > 0;
} Prevention
- Constrain permalink route patterns so only \d+ reaches the page slot.
- Validate page params at the controller/router boundary and 404 on non-numeric values.
- Audit theme next/prev link generation to always emit integers.
When it happens
Trigger: A theme page request whose page path/param is non-numeric, e.g. /page/abc/ or ?page=next. A permalink rule or rewrite that injects a non-integer segment into the page position. A crawler hitting an old or malformed page URL.
Common situations: Custom permalink patterns that accidentally route non-numeric tokens into the page slot; migration from a CMS whose page URLs used words; bots probing arbitrary path segments under /page/.
AI-assisted analysis of halo-dev/halo@d2f5165f9c (2026-08-14).
Data as JSON: /api/errors/d20eab0862003190.
Report an issue: GitHub.