{"record":{"id":"954844c801b74986","repo":"apereo/cas","slug":"missing-required-project-metadata-for-projectnam","errorCode":null,"errorMessage":"Missing required project metadata for ${projectName}","messagePattern":"Missing required project metadata for (.+?)","errorType":"console","errorClass":"GradleException","httpStatus":null,"severity":"error","filePath":"build.gradle","lineNumber":344,"sourceCode":"}\n\ndef projectModulesMetadataTaskRequested = CasBuildSettings.isTaskRequested(project, 'generateProjectModulesMetadata') ||\n    CasBuildSettings.isTaskRequested(project, 'publishProjectModulesMetadata')\nif (projectModulesMetadataTaskRequested) {\n    def modulesOutputFile = layout.buildDirectory.file('modules.json')\n    def projectVersion = version.toString().replaceAll('-SNAPSHOT', '')\n    def projectGroup = group.toString()\n    def moduleMetadataResults = CasBuildSettings.includedProjectPaths(project)\n        .findAll { projectPath -> projectPath != project.path }\n        .collectMany { projectPath ->\n            def moduleInfo = CasBuildSettings.projectModuleMetadata(project, projectPath)\n            if (!moduleInfo.publishMetadata) {\n                return []\n            }\n            def projectName = CasBuildSettings.projectNameFromPath(projectPath)\n            def metadata = new LinkedHashMap<>(moduleInfo.projectMetadata as Map)\n            if (!metadata.containsKey('title') || !metadata.containsKey('category')) {\n                throw new GradleException(\"Missing required project metadata for ${projectName}\")\n            }\n            if (!metadata.containsKey('selectable')) {\n                metadata.put('selectable', true)\n            }\n            return [[\n                name       : projectName,\n                version    : projectVersion,\n                group      : projectGroup,\n                description: moduleInfo.description,\n                details    : metadata\n            ]]\n        }\n    def moduleMetadataJson = groovy.json.JsonOutput.toJson(moduleMetadataResults)\n\n    def generateProjectModulesMetadata = tasks.register('generateProjectModulesMetadata') {\n        outputs.file(modulesOutputFile)\n        doLast {\n            def output = modulesOutputFile.get().asFile","sourceCodeStart":326,"sourceCodeEnd":362,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/build.gradle#L326-L362","documentation":"While generating project module metadata (for the CAS module/dependency catalog), build.gradle requires every publishable module to declare both 'title' and 'category' in its projectMetadata map; if either key is missing it throws GradleException(\"Missing required project metadata for ${projectName}\").","triggerScenarios":"Adding or renaming a module whose entry in the metadata map (moduleInfo.projectMetadata) lacks 'title' or 'category', then requesting generateProjectModulesMetadata / publishProjectModulesMetadata.","commonSituations":"Contributor creates a new module and forgets to add its metadata entry; a module is renamed so its metadata lookup misses; metadata file edited and a key typo'd as 'titel'/'catgeory'.","solutions":["Add 'title' and 'category' entries to the module's projectMetadata definition (see the metadata table in the build configuration).","If the module shouldn't be published, set publishMetadata = false for it.","Check for key typos and that the module path maps to the expected metadata entry."],"exampleFix":"// before\nprojectMetadata = [selectable: true]\n// after\nprojectMetadata = [title: 'CAS YubiKey Support', category: 'Authentication', selectable: true]","handlingStrategy":"validation","validationCode":"// verify metadata keys before running metadata tasks\ndef md = moduleInfo.projectMetadata as Map\nassert md.title && md.category : \"module ${projectPath} needs title and category\"","typeGuard":"static boolean hasRequiredMetadata(Map metadata) {\n    return metadata?.containsKey('title') && metadata?.containsKey('category');\n}","tryCatchPattern":null,"preventionTips":["Copy the metadata block from an existing sibling module when adding a new one.","Keep module names and metadata entries in sync during renames.","Run generateProjectModulesMetadata locally before pushing new modules."],"tags":["gradle","metadata","build","module"],"backgroundTag":"missing-required-config-field","analyzedSha":"e7288fc434b4f4505b8452e1a57e8fb3111bb863","analyzedAt":"2026-09-08T15:39:16.015Z","contentChangedAt":"2026-09-08T15:39:16.015Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}