{"record":{"id":"afd1949262029d60","repo":"zylon-ai/private-gpt","slug":"no-reader-registered-for-extension-extension","errorCode":null,"errorMessage":"No reader registered for extension: {extension}","messagePattern":"No reader registered for extension: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"private_gpt/components/readers/reader_component.py","lineNumber":33,"sourceCode":"\n\n@singleton\nclass ReaderComponent:\n    @inject\n    def __init__(\n        self,\n        settings: Settings,\n        reader_registry: ReaderRegistry,\n        reader_factory_registry: ReaderFactoryRegistry,\n    ) -> None:\n        self.settings = settings\n        self.registry = reader_registry\n        self.factory_registry = reader_factory_registry\n\n    def get_reader_by_extension(self, extension: str) -> IngestionReader:\n        reader_names = self.get_reader_names(extension=extension)\n        if not reader_names:\n            raise ValueError(f\"No reader registered for extension: {extension}\")\n        return self.get_reader(reader_names[0], extension)\n\n    def get_reader(\n        self,\n        name: str | None = None,\n        extension: str | None = None,\n    ) -> IngestionReader:\n        reader_names = self.get_reader_names(name=name, extension=extension)\n        if not reader_names:\n            raise ValueError(f\"No reader available for extension: {extension}\")\n        target_name = reader_names[0]\n        factory = self.factory_registry.get_factory(target_name)\n        return factory.create_reader(extension)\n\n    def get_registered_reader_name(self, extension: str | None) -> str | None:\n        return self.registry.get_reader_name(extension)\n\n    def get_reader_names(","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/zylon-ai/private-gpt/blob/4a030776a31a901ad80b1bf4d7faa2c1a367efbb/private_gpt/components/readers/reader_component.py#L15-L51","documentation":"ReaderComponent.get_reader_by_extension looks up reader names for a file extension in the registry; if no reader is registered for that extension at all, it raises ValueError. This means the extension was never mapped (neither built-in defaults nor custom registrations cover it), so the system has no way to parse the file. It is distinct from error 204, which covers the name/extension combined lookup in get_reader.","triggerScenarios":"Calling get_reader_by_extension(ext) for an extension absent from the reader registry — e.g. '.xyz', an extension whose reader was never registered, or after unregister_reader_factory removed the only reader for it.","commonSituations":"Ingesting an unsupported file type (.docx legacy, .heic, proprietary formats); forgetting to register a custom reader factory plus its extension mapping; a typo in the extension (uppercase '.PDF' vs '.pdf' if normalization is missing); disabling a reader at config time.","solutions":["Check the registry contents (get_reader_names / get_registered_reader_name) and confirm the exact extension string, lowercased and dot-prefixed, is registered.","Register a reader for the extension: component.register_reader_factory(name, factory) plus register_extension_reader(ext, name).","If the format is genuinely unsupported, convert the file to a supported format (e.g. .pdf, .txt, .csv) before ingestion.","Normalize the extension (`Path(f).suffix.lower()`) before calling the API — mismatched case is a common silent cause."],"exampleFix":"# before\nreader = component.get_reader_by_extension(\".DOCX\")  # ValueError: No reader registered\n\n# after\next = Path(file_name).suffix.lower()\nreader = component.get_reader_by_extension(ext)","handlingStrategy":"validation","validationCode":"from pathlib import Path\n\nSUPPORTED = {\".csv\", \".tsv\", \".psv\", \".eml\", \".pdf\", \".txt\", \".md\", \".html\"}  # adjust to your registration set\n\ndef can_ingest(file_name: str) -> bool:\n    return Path(file_name).suffix.lower() in SUPPORTED","typeGuard":null,"tryCatchPattern":"try:\n    reader = component.get_reader_by_extension(ext)\nexcept ValueError as e:\n    logger.warning(\"Unsupported extension, skipping file: %s\", e)\n    return None","preventionTips":["Normalize extensions with Path(f).suffix.lower() before lookup.","Keep a whitelist of ingestible extensions validated at the upload boundary.","Register custom readers at app startup so lookups never hit unregistered extensions."],"tags":["ingestion","reader-registry","file-type","validation"],"backgroundTag":null,"analyzedSha":"4a030776a31a901ad80b1bf4d7faa2c1a367efbb","analyzedAt":"2026-08-15T03:51:26.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}