{"record":{"id":"1b591647f42976f3","repo":"elastic/elasticsearch","slug":"license-category-name-must-be-exactly-5-characters","errorCode":null,"errorMessage":"License category name must be exactly 5 characters, got ${categoryName}","messagePattern":"License category name must be exactly 5 characters, got (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"build-conventions/src/main/java/org/elasticsearch/gradle/internal/conventions/precommit/LicenseHeadersTask.java","lineNumber":167,"sourceCode":"     * followed by the family name and the value list of patterns to search for.\n     */\n    @Input\n    public ListProperty<License> getAdditionalLicenses() {\n        return additionalLicenses;\n    }\n\n    /**\n     * Add a new license type.\n     * <p>\n     * The license may be added to the {@link #approvedLicenses} using the {@code familyName}.\n     *\n     * @param categoryName A 5-character string identifier for the license\n     * @param familyName   An expanded string name for the license\n     * @param pattern      A pattern to search for, which if found, indicates a file contains the license\n     */\n    public void additionalLicense(final String categoryName, String familyName, String pattern) {\n        if (categoryName.length() != 5) {\n            throw new IllegalArgumentException(\"License category name must be exactly 5 characters, got \" + categoryName);\n        }\n\n        additionalLicenses.add(new License(categoryName, familyName, pattern));\n    }\n\n    @TaskAction\n    public void runRat() {\n        ReportConfiguration reportConfiguration = new ReportConfiguration();\n        reportConfiguration.setAddingLicenses(true);\n        List<IHeaderMatcher> matchers = new ArrayList<>();\n        matchers.add(Defaults.createDefaultMatcher());\n\n        // BSD 4-clause stuff (is disallowed below)\n        // we keep this here, in case someone adds BSD code for some reason, it should never be allowed.\n        matchers.add(subStringMatcher(\"BSD4 \", \"Original BSD License (with advertising clause)\", \"All advertising materials\"));\n        // Apache\n        matchers.add(subStringMatcher(\"AL   \", \"Apache\", \"Licensed to Elasticsearch B.V. under one or more contributor\"));\n        matchers.add(subStringMatcher(\"AL   \", \"Apache\", \"Copyright Elasticsearch B.V., and/or licensed to Elasticsearch B.V.\"));","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/build-conventions/src/main/java/org/elasticsearch/gradle/internal/conventions/precommit/LicenseHeadersTask.java#L149-L185","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pad or trim categoryName to exactly 5 characters, e.g. \"BSD  \" or \"APCH2\".","Mirror the existing convention seen in subStringMatcher calls like \"AL   \", \"GEN  \", \"VEN  \".","Add a unit test asserting the length when introducing a new license family."],"exampleFix":"// before\nlicenseHeaders.additionalLicense('BSD', 'BSD License', 'Redistribution and use')\n// after\nlicenseHeaders.additionalLicense('BSD  ', 'BSD License', 'Redistribution and use')","handlingStrategy":"validation","validationCode":"static String licenseCategory(String name) {\n    Objects.requireNonNull(name, \"categoryName\");\n    if (name.length() != 5) {\n        throw new IllegalArgumentException(\"categoryName must be 5 chars: \" + name);\n    }\n    return name;\n}\nlicenseHeaders.additionalLicense(licenseCategory(myCode), family, pattern);","typeGuard":"static boolean isValidLicenseCategory(String s) {\n    return s != null && s.length() == 5;\n}","tryCatchPattern":null,"preventionTips":["Pad category codes to 5 characters with trailing spaces, matching existing codes like \"AL   \".","Unit-test any new additionalLicense call against the length invariant.","Centralise license registration in one build script to avoid ad-hoc values."],"tags":["gradle","license","validation","build-script"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}