{"id":"2a1fa6505282682e","repo":"pypa/pip","slug":"dynamic-upload-time-missing-detail","errorCode":null,"errorMessage":"<dynamic: upload-time missing detail>","messagePattern":"<dynamic: upload-time missing detail>","errorType":"exception","errorClass":"InstallationError","httpStatus":null,"severity":"error","filePath":"src/pip/_internal/index/package_finder.py","lineNumber":828,"sourceCode":"    def _log_skipped_link(self, link: Link, result: LinkType, detail: str) -> None:\n        # Put the link at the end so the reason is more visible and because\n        # the link string is usually very long.\n        logger.debug(\"Skipping link: %s: %s\", detail, link)\n        if result == LinkType.requires_python_mismatch:\n            self._requires_python_skipped.add(detail)\n\n    def get_install_candidate(\n        self, link_evaluator: LinkEvaluator, link: Link\n    ) -> InstallationCandidate | None:\n        \"\"\"\n        If the link is a candidate for install, convert it to an\n        InstallationCandidate and return it. Otherwise, return None.\n        \"\"\"\n        result, detail = link_evaluator.evaluate_link(link)\n        if result == LinkType.upload_time_missing:\n            # Fail immediately if the index doesn't provide upload-time\n            # when --uploaded-prior-to is specified\n            raise InstallationError(detail)\n        if result != LinkType.candidate:\n            self._log_skipped_link(link, result, detail)\n            return None\n\n        try:\n            return InstallationCandidate(\n                name=link_evaluator.project_name,\n                link=link,\n                version=detail,\n            )\n        except InvalidVersion:\n            return None\n\n    def evaluate_links(\n        self, link_evaluator: LinkEvaluator, links: Iterable[Link]\n    ) -> list[InstallationCandidate]:\n        \"\"\"\n        Convert links that are candidates to InstallationCandidate objects.","sourceCodeStart":810,"sourceCodeEnd":846,"githubUrl":"https://github.com/pypa/pip/blob/d7d0d0a39494e28ec1c407bd0680e4a4d1067791/src/pip/_internal/index/package_finder.py#L810-L846","documentation":"InstallationError raised in get_install_candidate when a candidate link's evaluation returns LinkType.upload_time_missing while --uploaded-prior-to is in effect. pip requires every index/file link to carry an upload timestamp to honour that filter; a link lacking it fails immediately rather than being silently skipped.","triggerScenarios":"Invoking pip with --uploaded-prior-to <datetime> against an index or find-links source that does not expose the file's upload/release time (e.g. a flat directory listing, a legacy Simple JSON without upload_time, or an HTML index without a recognizable date). link_evaluator.evaluate_link returns upload_time_missing and the code converts it to a hard error.","commonSituations":"Using --uploaded-prior-to for reproducible/supply-chain installs against a private index that strips timestamps; a custom Simple repository (PEP 503 HTML) that omits the data-attributes; pointing find-links at a local folder (no upload time concept) while the flag is set.","solutions":["Remove --uploaded-priorite if you do not strictly need the time filter; that converts the failure back to a skip.","Point pip at an index that provides upload times (PEP 69 JSON API or Simple HTML with proper date attributes).","If using a private index, configure it to emit upload-time metadata for each file.","Use a lockfile/resolver that records exact files instead of relying on index timestamps."],"exampleFix":"# before\npip install --uploaded-priorite 2024-01-01T00:00:00Z -f ./wheels/ somepkg\n\n# after (drop the filter, or use a timestamp-providing index)\npip install somepkg\n# or\npip install -i https://pypi.org/simple/ --uploaded-priorite 2024-01-01 somepkg","handlingStrategy":"validation","validationCode":"# before using --uploaded-prior-to, check the index exposes timestamps\nimport urllib.request, json\nurl = 'https://pypi.org/pypi/somepkg/json'\ndata = json.load(urllib.request.urlopen(url))\nfor f in data['urls']:\n    if 'upload_time' not in f:\n        print('index lacks upload_time - do not use --uploaded-priorite')","typeGuard":"def index_has_upload_time(index_url: str, project: str) -> bool:\n    import urllib.request, json\n    d = json.load(urllib.request.urlopen(f'{index_url}/{project}/json'))\n    return all('upload_time' in f for f in d['urls'])","tryCatchPattern":"from pip._internal.exceptions import InstallationError\ntry:\n    finder.get_install_candidate(link_evaluator, link)\nexcept InstallationError as e:\n    if 'upload' in str(e).lower():\n        # drop --uploaded-priorite or switch index\n        ...","preventionTips":["Only use --uploaded-priorite with indexes that publish upload times.","Prefer PyPI JSON API or PEP 69 JSON for timestamp data.","Avoid --uploaded-priorite against local --find-links directories.","Use a lockfile for reproducibility instead of timestamp filtering."],"tags":["index","supply-chain","uploaded-priorite","metadata"],"analyzedSha":"d7d0d0a39494e28ec1c407bd0680e4a4d1067791","analyzedAt":"2026-08-04T20:55:04.259Z","schemaVersion":2}