{"record":{"id":"34e7d11bea8bf4c7","repo":"pypa/pip","slug":"uninstall-no-record-file","errorCode":"uninstall-no-record-file","errorMessage":"Cannot uninstall {distribution}","messagePattern":"Cannot uninstall (.+?)","errorType":"exception","errorClass":"UninstallMissingRecord","httpStatus":null,"severity":"error","filePath":"src/pip/_internal/req/req_uninstall.py","lineNumber":77,"sourceCode":"    \"\"\"\n    Yield all the uninstallation paths for dist based on RECORD-without-.py[co]\n\n    Yield paths to all the files in RECORD. For each .py file in RECORD, add\n    the .pyc and .pyo in the same directory.\n\n    UninstallPathSet.add() takes care of the __pycache__ .py[co].\n\n    If RECORD is not found, raises an error,\n    with possible information from the INSTALLER file.\n\n    https://packaging.python.org/specifications/recording-installed-packages/\n    \"\"\"\n    location = dist.location\n    assert location is not None, \"not installed\"\n\n    entries = dist.iter_declared_entries()\n    if entries is None:\n        raise UninstallMissingRecord(distribution=dist)\n\n    for entry in entries:\n        path = os.path.join(location, entry)\n        yield path\n        if path.endswith(\".py\"):\n            dn, fn = os.path.split(path)\n            base = fn[:-3]\n            path = os.path.join(dn, base + \".pyc\")\n            yield path\n            path = os.path.join(dn, base + \".pyo\")\n            yield path\n\n\ndef compact(paths: Iterable[str]) -> set[str]:\n    \"\"\"Compact a path set to contain the minimal number of paths\n    necessary to contain all paths in the set. If /a/path/ and\n    /a/path/to/a/file.txt are both in the set, leave only the\n    shorter path.\"\"\"","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/pypa/pip/blob/f399c3718970b1b0e2478dac5296eb62679a9b86/src/pip/_internal/req/req_uninstall.py#L59-L95","documentation":"uninstallation_paths (req_uninstall.py:77) raises UninstallMissingRecord (DiagnosticPipError, code uninstall-no-record-file) when dist.iter_declared_entries() returns None — meaning the package's .dist-info/RECORD is absent. Without RECORD pip cannot enumerate which files to remove, so it refuses rather than do a partial uninstall.","triggerScenarios":"Running pip uninstall on a package whose .dist-info lacks a RECORD file — installed by a non-pip tool (conda, easy_install, hand-copy, system package manager).","commonSituations":"Conda-installed packages in a shared env; packages copied manually; legacy easy_install eggs; partial/corrupted installs.","solutions":["Force a clean reinstall then uninstall: pip install --ignore-installed --no-deps <pkg>==<ver> then pip uninstall <pkg>.","Use the original installer (conda remove, apt purge) to remove the package.","Manually delete the package files and its .dist-info directory."],"exampleFix":"# before\npip uninstall corruptedpkg  # fails: no RECORD\n# after\npip install --ignore-installed --no-deps corruptedpkg==1.0 && pip uninstall corruptedpkg","handlingStrategy":"validation","validationCode":"# Before pip uninstall, check whether a RECORD file exists.\nimport importlib.metadata as md, pathlib, sys\ntarget = sys.argv[2]  # e.g. pkg name\ntry:\n    dist = md.distribution(target)\n    record = pathlib.Path(dist._path) / \"RECORD\"  # type: ignore\n    if not record.exists():\n        print(f\"WARNING: {target} has no RECORD; reinstall first:\",\n              f\"pip install --ignore-installed --no-deps {target}=={dist.version}\")\nexcept md.PackageNotFoundError:\n    pass","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Prefer installing packages with pip so they get a RECORD file.","Don't mix conda/system installs with pip in the same env.","Before uninstalling, check for a .dist-info/RECORD file."],"tags":["uninstall","record","metadata"],"backgroundTag":null,"analyzedSha":"f399c3718970b1b0e2478dac5296eb62679a9b86","analyzedAt":"2026-08-08T23:01:42.227Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}