{"record":{"id":"7bc84dff3254f459","repo":"squidfunk/mkdocs-material","slug":"relative-path-processor-not-registered","errorCode":null,"errorMessage":"Relative path processor not registered","messagePattern":"Relative path processor not registered","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/extensions/preview.py","lineNumber":76,"sourceCode":"        Run the treeprocessor.\n\n        Arguments:\n            root: The root element of the parsed Markdown document.\n        \"\"\"\n        at = self.md.treeprocessors.get_index_for_name(\"relpath\")\n\n        # Hack: Python Markdown has no notion of where it is, i.e., which file\n        # is being processed. This seems to be a deliberate design decision, as\n        # it is not possible to access the file path of the current page, but\n        # it might also be an oversight that is now impossible to fix. However,\n        # since this extension is only useful in the context of Material for\n        # MkDocs, we can assume that the _RelativePathTreeprocessor is always\n        # present, telling us the file path of the current page. If that ever\n        # changes, we would need to wrap this extension in a plugin, but for\n        # the time being we are sneaky and will probably get away with it.\n        processor = self.md.treeprocessors[at]\n        if not isinstance(processor, _RelativePathTreeprocessor):\n            raise TypeError(\"Relative path processor not registered\")\n\n        # Normalize configurations\n        configurations = self.config[\"configurations\"]\n        configurations.append({\n            \"sources\": self.config.get(\"sources\"),\n            \"targets\": self.config.get(\"targets\")\n        })\n\n        # Walk through all configurations - @todo refactor so that we don't\n        # iterate multiple times over the same elements\n        for configuration in configurations:\n\n            # Skip, if the configuration defines nothing – we could also fix\n            # this in the file filter, but we first fix it here and check if\n            # it generalizes well enough to other inclusion/exclusion sites,\n            # because here, it would hinder the ability to automaticaly\n            # include all sources, while excluding specific targets.\n            if (","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/squidfunk/mkdocs-material/blob/e2136532f40aed98af1f6497c0cc6a3cff9f759b/src/extensions/preview.py#L58-L94","documentation":"The preview extension's run() hooks into Markdown conversion and relies on markdown's built-in _RelativePathTreeprocessor to know the current page's file path. It looks the processor up in md.treeprocessors and throws a TypeError if the registered processor at that priority slot is not the expected _RelativePathTreeprocessor. This happens when the markdown library's internal pipeline changes (different version or competing extensions).","triggerScenarios":"Running preview with a markdown/Markdown version where _RelativePathTreeprocessor is no longer registered at the expected priority; another extension registering a treeprocessor at that slot; markdown internals refactored/renamed in an upgrade.","commonSituations":"Upgrading the markdown package beyond what mkdocs-material supports; installing plugins that inject custom treeprocessors at the same priority; running mkdocs against an unusual/newer markdown release.","solutions":["Pin the markdown package to a version compatible with your mkdocs-material release (check material's requirements).","Disable or reorder third-party Markdown extensions that register treeprocessors at the same priority slot.","If you maintain the integration, look the processor up by class name instead of a fixed priority key."],"exampleFix":"# before (requirements.txt)\nmarkdown>=3.3\n\n# after\nmarkdown>=3.3,<3.5","handlingStrategy":"validation","validationCode":"import markdown\nfrom mkdocs_extensions_preview import _RelativePathTreeprocessor\nmd = markdown.Markdown(extensions=[...])\nassert any(isinstance(p, _RelativePathTreeprocessor) for p in md.treeprocessors), (\n    \"markdown version incompatible: relative path treeprocessor missing\"\n)","typeGuard":"def is_relative_path_processor(md) -> bool:\n    proc = md.treeprocessors[150] if 150 in md.treeprocessors else None\n    return isinstance(proc, _RelativePathTreeprocessor)","tryCatchPattern":"try:\n    extensions = [Preview()]  # or via mkdocs.yml\nexcept TypeError as e:\n    if \"Relative path processor\" in str(e):\n        # markdown version mismatch: pin/downgrade markdown\n        raise SystemExit(\"Upgrade/downgrade the 'markdown' package\")\n    raise","preventionTips":["Pin the markdown dependency to the range mkdocs-material declares in its requirements.","Test mkdocs builds in CI after any dependency bump.","Avoid extensions that hijack the same treeprocessor priority slot.","Read changelogs of the markdown package before upgrading."],"tags":["python","mkdocs","markdown","extension"],"backgroundTag":"incompatible-library-version","analyzedSha":"e2136532f40aed98af1f6497c0cc6a3cff9f759b","analyzedAt":"2026-08-29T11:20:04.299Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}