halo-dev/halo · error · IllegalArgumentException
Unexpected APIVersion string: {}
Error message
Unexpected APIVersion string: {} What it means
Thrown by GroupVersion.parseAPIVersion when the apiVersion string, after splitting on '/', yields more than 2 segments. Halo encodes an Extension's apiVersion as either 'version' (empty group) or 'group/version'; a string with 2+ slashes (e.g. 'a/b/c') has no valid group/version mapping and is rejected. The blank-input case is caught earlier by Assert.hasText.
Source
Thrown at api/src/main/java/run/halo/app/extension/GroupVersion.java:34
public String toString() {
return StringUtils.hasText(group) ? group + "/" + version : version;
}
/**
* Parses APIVersion into GroupVersion record.
*
* @param apiVersion must not be blank. 1. If the given apiVersion does not contain any "/", we treat the group is
* empty. 2. If the given apiVersion contains more than 1 "/", we will throw an IllegalArgumentException.
* @return record contains group and version.
*/
public static GroupVersion parseAPIVersion(String apiVersion) {
Assert.hasText(apiVersion, "API version must not be blank");
var groupVersion = apiVersion.split("/");
return switch (groupVersion.length) {
case 1 -> new GroupVersion("", apiVersion);
case 2 -> new GroupVersion(groupVersion[0], groupVersion[1]);
default -> throw new IllegalArgumentException("Unexpected APIVersion string: " + apiVersion);
};
}
}
View on GitHub (pinned to d2f5165f9c)
Solutions
- Pass apiVersion strictly as 'group/version' (e.g. 'content.halo.run/v1alpha1') or just 'version' for core resources.
- Strip anything after the second segment before calling parseAPIVersion.
- Validate with `apiVersion.chars().filter(c -> c == '/').count() <= 1` before parsing.
Example fix
// before
GroupVersion.parseAPIVersion("content.halo.run/v1alpha1/posts");
// after
GroupVersion.parseAPIVersion("content.halo.run/v1alpha1"); Defensive patterns
Strategy: validation
Validate before calling
long slashes = apiVersion.chars().filter(c -> c == '/').count();
if (slashes > 1) {
throw new IllegalArgumentException("apiVersion must be 'group/version' or 'version': " + apiVersion);
}
GroupVersion gv = GroupVersion.parseAPIVersion(apiVersion); Type guard
boolean validApiVersion = apiVersion != null && !apiVersion.isBlank()
&& apiVersion.chars().filter(c -> c == '/').count() <= 1; Try / catch
try {
GroupVersion gv = GroupVersion.parseAPIVersion(apiVersion);
} catch (IllegalArgumentException e) {
// log and reject the malformed resource
} Prevention
- Construct apiVersion from GroupVersion.toString() rather than string concatenation.
- Reject resources whose apiVersion has >1 '/' at the deserialization boundary.
- Never append a kind or subresource to the apiVersion string.
When it happens
Trigger: GroupVersion.parseAPIVersion("content.halo.run/v1alpha1/extra"), parseAPIVersion("a/b/c"), or any apiVersion containing more than one '/'.
Common situations: A client concatenates group + '/' + version + '/' + subresource; an extension GVK string mis-parsed to include a trailing slash segment; a URL path fragment mistaken for apiVersion; copied 'group/version/kind' instead of 'group/version'.
Related errors
- No such thumbnail size: {}
- Unsupported operator: {}
- No value present for label key: {}
- No value present for label key: {}
- Failed to validate {gvk}
AI-assisted analysis of halo-dev/halo@d2f5165f9c (2026-08-14).
Data as JSON: /api/errors/396401e092f5ef87.
Report an issue: GitHub.