{"record":{"id":"51f96980075323ac","repo":"oracle/graal","slug":"the-relative-home-path-of-language-is-already-se","errorCode":null,"errorMessage":"the relative home path of {language} is already set to {self.relative_home_paths[language]} and cannot also be set to {path} for {self.destination}","messagePattern":"the relative home path of (.+?) is already set to (.+?) and cannot also be set to (.+?) for (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"sdk/mx.sdk/mx_sdk_vm.py","lineNumber":140,"sourceCode":"        for required in required_exports:\n            target_modules = required_exports[required]\n            target_modules_str = custom_target_module_str or ','.join(sorted(target_module.name for target_module in target_modules))\n            required_module_name, required_package_name = required\n            add_exports.append('--add-exports=' + required_module_name + '/' + required_package_name + \"=\" + target_modules_str)\n        return sorted(add_exports)\n\n    def get_add_exports(self, missing_jars):\n        if self.use_modules is None:\n            return ''\n        distributions = self.jar_distributions\n        distributions_transitive = mx.classpath_entries(distributions)\n        distributions_transitive_clean = [entry for entry in distributions_transitive if str(entry) not in missing_jars]\n        required_exports = mx_javamodules.requiredExports(distributions_transitive_clean, base_jdk())\n        return AbstractNativeImageConfig.get_add_exports_list(required_exports)\n\n    def add_relative_home_path(self, language, path):\n        if language in self.relative_home_paths and self.relative_home_paths[language] != path:\n            raise ValueError(f'the relative home path of {language} is already set to {self.relative_home_paths[language]} and cannot also be set to {path} for {self.destination}')\n        self.relative_home_paths[language] = path\n\n    def add_relative_extracted_lib_path(self, name, path):\n        if name in self.relative_extracted_lib_paths and self.relative_extracted_lib_paths[name] != path:\n            raise ValueError(f'the relative extracted lib path of {name} is already set to {self.relative_extracted_lib_paths[name]} and cannot also be set to {path} for {self.destination}')\n        self.relative_extracted_lib_paths[name] = path\n\nclass LauncherConfig(AbstractNativeImageConfig):\n    def __init__(self, destination, jar_distributions, main_class, build_args, is_main_launcher=True,\n                 default_symlinks=True, is_sdk_launcher=False, custom_launcher_script=None, extra_jvm_args=None,\n                 use_modules=None, main_module=None, link_at_build_time=True, option_vars=None, home_finder=True, **kwargs):\n        \"\"\"\n        :param str main_class\n        :param bool is_main_launcher\n        :param bool default_symlinks\n        :param bool is_sdk_launcher: Whether it uses org.graalvm.launcher.Launcher\n        :param str custom_launcher_script: Custom launcher script, to be used when not compiled as a native image\n        :param list[str] | None extra_jvm_args","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/sdk/mx.sdk/mx_sdk_vm.py#L122-L158","documentation":"While building a GraalVM image layout, add_relative_home_path() records where each language's home directory lives relative to the image. A language may only have one relative home path per destination; registering a second, different path raises ValueError to surface a suite configuration conflict.","triggerScenarios":"Two components/suite.py entries calling add_relative_home_path('language-X', p1) and add_relative_home_path('language-X', p2) with p1 != p2 for the same image destination.","commonSituations":"Editing suite.py to relocate a language home; adding a new language that reuses an existing language key; copying a component config and forgetting to change the language name.","solutions":["Inspect the message for both paths, find the two components registering the language, and make them agree (same path) in suite.py.","If two distinct homes are genuinely needed, give the second one a different language key or destination.","Re-run the layout build after fixing to confirm the conflict is gone."],"exampleFix":"# before (suite.py)\ncomponent A: add_relative_home_path('python', 'languages/python')\ncomponent B: add_relative_home_path('python', 'python')   # conflict\n\n# after\ncomponent B: add_relative_home_path('python', 'languages/python')","handlingStrategy":"validation","validationCode":"def add_relative_home_path_checked(cfg, language, path):\n    existing = cfg.relative_home_paths.get(language)\n    if existing is not None and existing != path:\n        raise ValueError(f\"{language} home already {existing}; refusing to set {path}\")\n    cfg.relative_home_paths[language] = path","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep exactly one component responsible for each language's home path per destination.","When moving a language home, update all registrations in the same change and grep for the language key.","Add a suite-level consistency check over relative_home_paths before layout builds."],"tags":["graalvm","build","layout","configuration","mx"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}