elastic/elasticsearch · error · IllegalArgumentException

License category name must be exactly 5 characters, got ${ca

Error message

License category name must be exactly 5 characters, got ${categoryName}

What it means

Apache RAT (used by LicenseHeadersTask) identifies license families by a fixed-width 5-character category code that goes into the XML report. additionalLicense enforces this invariant up front so a malformed category cannot corrupt the report later. The message prints the offending value.

Source

Thrown at build-conventions/src/main/java/org/elasticsearch/gradle/internal/conventions/precommit/LicenseHeadersTask.java:167

     * followed by the family name and the value list of patterns to search for.
     */
    @Input
    public ListProperty<License> getAdditionalLicenses() {
        return additionalLicenses;
    }

    /**
     * Add a new license type.
     * <p>
     * The license may be added to the {@link #approvedLicenses} using the {@code familyName}.
     *
     * @param categoryName A 5-character string identifier for the license
     * @param familyName   An expanded string name for the license
     * @param pattern      A pattern to search for, which if found, indicates a file contains the license
     */
    public void additionalLicense(final String categoryName, String familyName, String pattern) {
        if (categoryName.length() != 5) {
            throw new IllegalArgumentException("License category name must be exactly 5 characters, got " + categoryName);
        }

        additionalLicenses.add(new License(categoryName, familyName, pattern));
    }

    @TaskAction
    public void runRat() {
        ReportConfiguration reportConfiguration = new ReportConfiguration();
        reportConfiguration.setAddingLicenses(true);
        List<IHeaderMatcher> matchers = new ArrayList<>();
        matchers.add(Defaults.createDefaultMatcher());

        // BSD 4-clause stuff (is disallowed below)
        // we keep this here, in case someone adds BSD code for some reason, it should never be allowed.
        matchers.add(subStringMatcher("BSD4 ", "Original BSD License (with advertising clause)", "All advertising materials"));
        // Apache
        matchers.add(subStringMatcher("AL   ", "Apache", "Licensed to Elasticsearch B.V. under one or more contributor"));
        matchers.add(subStringMatcher("AL   ", "Apache", "Copyright Elasticsearch B.V., and/or licensed to Elasticsearch B.V."));

View on GitHub (pinned to db6a809a66)

Solutions

  1. Pad or trim categoryName to exactly 5 characters, e.g. "BSD " or "APCH2".
  2. Mirror the existing convention seen in subStringMatcher calls like "AL ", "GEN ", "VEN ".
  3. Add a unit test asserting the length when introducing a new license family.

Example fix

// before
licenseHeaders.additionalLicense('BSD', 'BSD License', 'Redistribution and use')
// after
licenseHeaders.additionalLicense('BSD  ', 'BSD License', 'Redistribution and use')
Defensive patterns

Strategy: validation

Validate before calling

static String licenseCategory(String name) {
    Objects.requireNonNull(name, "categoryName");
    if (name.length() != 5) {
        throw new IllegalArgumentException("categoryName must be 5 chars: " + name);
    }
    return name;
}
licenseHeaders.additionalLicense(licenseCategory(myCode), family, pattern);

Type guard

static boolean isValidLicenseCategory(String s) {
    return s != null && s.length() == 5;
}

Prevention

When it happens

Trigger: A build script calls additionalLicense("BSD", ...) or additionalLicense("APACHE2", ...) — any categoryName whose length is not exactly 5. This is a build-author programming error, not a runtime or environment issue.

Common situations: A contributor adds a custom license family in a build.gradle and guesses the category length; copy-paste from another RAT integration that allowed variable-length codes; a typo trimming or padding the code.

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/1b591647f42976f3. Report an issue: GitHub.