{"record":{"id":"7b0a44f9c54df903","repo":"zylon-ai/private-gpt","slug":"template-template-name-does-not-have-a-source-or","errorCode":null,"errorMessage":"Template {template_name} does not have a source or filename.","messagePattern":"Template (.+?) does not have a source or filename\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"private_gpt/components/prompts/prompt_template.py","lineNumber":36,"sourceCode":"            trim_blocks=True,\n            lstrip_blocks=True,\n            extensions=[\"jinja2.ext.do\"],\n        )\n\n    def get_template(self, template_name: str) -> Template:\n        return self.env.get_template(template_name)\n\n    def get_template_str(self, template_name: str) -> str:\n        \"\"\"Get the template string from the template name.\"\"\"\n        template = self.get_template(template_name)\n        if hasattr(template, \"source\"):\n            return str(template.source)\n        elif hasattr(template, \"filename\") and template.filename:\n            template_path = Path(template.filename)\n            with open(template_path, encoding=\"utf-8\") as f:\n                return f.read()\n        else:\n            raise ValueError(\n                f\"Template {template_name} does not have a source or filename.\"\n            )\n\n    def create_prompt_template(\n        self,\n        template_name: str,\n        **template_kwargs: Any,\n    ) -> BasePromptTemplate:\n        template = self.get_template(template_name)\n        template_str = self.get_template_str(template_name)\n\n        def process_value(v: Any) -> Any:\n            if isinstance(v, list):\n                return [process_value(value) for value in v]\n            elif isinstance(v, dict):\n                return {\n                    process_value(key): process_value(val) for key, val in v.items()\n                }","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/zylon-ai/private-gpt/blob/4a030776a31a901ad80b1bf4d7faa2c1a367efbb/private_gpt/components/prompts/prompt_template.py#L18-L54","documentation":"`PromptTemplate.get_template_str` extracts a template's text from a Jinja environment template: it prefers `template.source`, falls back to reading `template.filename` from disk, and raises `ValueError` when the template object has neither a usable `source` attribute nor a truthy `filename`. This happens with Jinja Template objects created from non-filesystem loaders or dict loaders that strip these attributes.","triggerScenarios":"Loading prompts via a custom Jinja loader (e.g. DictLoader) whose Template objects lack `source`/`filename`; a template compiled from a string without source retention; calling `get_template_str`/`create_prompt_template` for a template name resolved through such an environment.","commonSituations":"Customizing the prompt environment or loaders; embedding prompts in code instead of files; Jinja version behavior differences in what attributes a lazily-loaded Template exposes before rendering.","solutions":["Use the standard file-based loader so resolved templates carry `filename`","Ensure the loader populates `source` on templates (e.g. wrap DictLoader values so templates keep their source)","Force template compile/resolve via `env.get_template(name)` before calling `get_template_str`, since the code path already calls `get_template` first"],"exampleFix":"# before\nenv = Environment(loader=DictLoader({\"my.prompt\": \"text {{x}}\"}))\n# template lacks source/filename -> ValueError\n\n# after\nenv = Environment(\n    loader=FileSystemLoader(\"private_gpt/components/prompts/templates\")\n)","handlingStrategy":"validation","validationCode":"template = prompt_env.get_template(name)\nif not (getattr(template, \"source\", None) or getattr(template, \"filename\", None)):\n    raise ValueError(f\"loader for {name!r} strips source/filename; use a file-based loader\")","typeGuard":"def template_is_readable(template: Any) -> bool:\n    return bool(getattr(template, \"source\", None)) or bool(getattr(template, \"filename\", None))","tryCatchPattern":"try:\n    template_str = prompts.get_template_str(name)\nexcept ValueError as e:\n    if \"does not have a source or filename\" in str(e):\n        raise ConfigurationError(\"prompt loader must keep source or filename\") from e\n    raise","preventionTips":["Use FileSystemLoader for prompt templates; avoid dict/string loaders on paths that call get_template_str","Test every registered template name through get_template_str in CI"],"tags":["prompts","jinja2","template-loader","configuration"],"backgroundTag":null,"analyzedSha":"4a030776a31a901ad80b1bf4d7faa2c1a367efbb","analyzedAt":"2026-08-15T03:51:26.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}