{"record":{"id":"cad7ec8aec9bc202","repo":"oraios/serena","slug":"unknown-placeholder-name-in-project-serena-fo","errorCode":null,"errorMessage":"Unknown placeholder '${name}' in project_serena_folder_location. Supported placeholders: {', '.join('$' + k for k in placeholders)}","messagePattern":"Unknown placeholder '(.+?)' in project_serena_folder_location\\. Supported placeholders: (.+?)","errorType":"exception","errorClass":"SerenaConfigError","httpStatus":null,"severity":"error","filePath":"src/serena/config/serena_config.py","lineNumber":1368,"sourceCode":"\n        save_yaml(self.config_file_path, commented_yaml)\n\n    @staticmethod\n    def _resolve_serena_folder_location(template: str, placeholders: dict[str, str]) -> str:\n        \"\"\"\n        Resolves a folder location template by replacing known ``$placeholder`` tokens\n        and raising on any unrecognised ones.\n\n        :param template: the template string (e.g. ``\"$projectDir/.serena\"``)\n        :param placeholders: mapping from placeholder name (without ``$``) to replacement value\n        :return: the resolved absolute path\n        :raises SerenaConfigError: if the template contains an unknown ``$placeholder``\n        \"\"\"\n\n        def _replace(match: re.Match[str]) -> str:\n            name = match.group(1)\n            if name not in placeholders:\n                raise SerenaConfigError(\n                    f\"Unknown placeholder '${name}' in project_serena_folder_location. \"\n                    f\"Supported placeholders: {', '.join('$' + k for k in placeholders)}\"\n                )\n            return placeholders[name]\n\n        result = re.sub(r\"\\$([A-Za-z_]\\w*)\", _replace, template)\n        return os.path.abspath(result)\n\n    def get_configured_project_serena_folder(self, project_root: str | Path) -> str:\n        \"\"\"\n        Returns the resolved absolute path to the .serena data folder for a project,\n        applying placeholder substitution to ``project_serena_folder_location``\n        without any fallback logic.\n\n        :param project_root: the absolute path to the project root directory\n        :return: the resolved absolute path to the project's .serena folder\n        :raises SerenaConfigError: if the template contains an unknown placeholder\n        \"\"\"","sourceCodeStart":1350,"sourceCodeEnd":1386,"githubUrl":"https://github.com/oraios/serena/blob/7fcbca7e62555ec2287ddb2f083caee805848ea6/src/serena/config/serena_config.py#L1350-L1386","documentation":"Serena expands `$placeholder` tokens in the `project_serena_folder_location` config template using a fixed placeholder map. If the template contains a `$NAME` that is not a key of that map, the `_replace` callback inside `re.sub` raises SerenaConfigError. This fails fast so a mis-typed template variable is caught at config-processing time instead of silently expanding to an empty string.","triggerScenarios":"Setting `project_serena_folder_location` in serena_config.yml to a value containing a `$`-prefixed token whose name is not in the placeholders dict (e.g. a typo like `$HOMEPROJECT` or a literal `$` followed by letters such as a shell variable or price string `$100usd`). Any code path that resolves this template calls `re.sub(r\"\\$([A-Za-z_]\\w*)\", _replace, template)` and raises on the first unknown name.","commonSituations":"Users copying shell-style variable syntax (`$PROJECT`) that the template doesn't support, typos in supported placeholder names, or pasting paths containing `$` + letters (e.g. macOS/brew paths or currency strings) into the config value.","solutions":["Replace the unknown `$NAME` with a supported placeholder listed in the error message (they are echoed verbatim).","If you meant a literal `$`, escape or remove it — the regex matches any `$` followed by a letter/underscore, so `$100` is safe but `$usd` is not.","Check serena_config.yml for shell-variable leftovers and remove them.","Update the placeholder map at the call site if a new placeholder is genuinely required (library change, not a config fix)."],"exampleFix":"# before (serena_config.yml)\nproject_serena_folder_location: \"$HOMEPROJ/.serena/projects\"\n# after\nproject_serena_folder_location: \"$project_root/.serena/projects\"","handlingStrategy":"validation","validationCode":"import re\ndef validate_placeholders(template: str, placeholders: dict[str, str]) -> list[str]:\n    return [n for n in re.findall(r\"\\$([A-Za-z_]\\w*)\", template) if n not in placeholders]","typeGuard":"def is_valid_template(template: str, placeholders: dict[str, str]) -> bool:\n    return not validate_placeholders(template, placeholders)","tryCatchPattern":"try:\n    path = config.expand_project_serena_folder_location()\nexcept SerenaConfigError as e:\n    logger.error(\"Fix project_serena_folder_location: %s\", e)\n    raise","preventionTips":["List supported placeholders (they are printed in the error) before writing the template.","Avoid literal `$` followed by letters in config values unless intended as a placeholder.","Validate the config template in CI before deploying.","Copy placeholder names from official docs instead of shell variable conventions."],"tags":["config","placeholder","template","python"],"backgroundTag":"unknown-template-placeholder","analyzedSha":"7fcbca7e62555ec2287ddb2f083caee805848ea6","analyzedAt":"2026-08-29T00:04:09.619Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}