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

  1. Pass apiVersion strictly as 'group/version' (e.g. 'content.halo.run/v1alpha1') or just 'version' for core resources.
  2. Strip anything after the second segment before calling parseAPIVersion.
  3. 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

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


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