{"record":{"id":"8aced6d6d8c5c1f5","repo":"pypa/pip","slug":"index-link-comes-from-does-not-provide-upload-ti","errorCode":null,"errorMessage":"Index {link.comes_from} does not provide upload-time metadata.","messagePattern":"Index (.+?) does not provide upload-time metadata\\.","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/f399c3718970b1b0e2478dac5296eb62679a9b86/src/pip/_internal/index/package_finder.py#L810-L846","documentation":"Raised by get_install_candidate when a LinkEvaluator returns LinkType.upload_time_missing. This happens when the --uploaded-prior-to option is set but the package index page (or find-links source) for the link does not include upload-time metadata for that file. Because pip cannot honor a date filter without a timestamp, it aborts immediately rather than silently skipping the constraint.","triggerScenarios":"Running `pip install --uploaded-prior-to <DATE> <pkg>` against a simple-index URL or --find-links directory whose PEP 503 page lacks the upload-time attribute on the link. The get_install_candidate method at package_finder.py:824 evaluates the link and, on result == LinkType.upload_time_missing, raises InstallationError(detail) where detail is the message.","commonSituations":"Private mirrors / internal indexes (devpi, Artifactory, Nexus simple repos) that strip or never emit upload timestamps; legacy flat find-links directories with no HTML wrapper; a mirror that only provides the file URL without HTTP Last-Modified-style metadata pip can map to upload time.","solutions":["Drop the --uploaded-prior-to flag if date-based filtering is not strictly required.","Point --index-url at a source that provides upload-time metadata (PyPI, or configure your mirror to include the upload-time attribute on simple-index links).","If using a local --find-links directory, regenerate the index HTML with a tool that records file mtime as upload time."],"exampleFix":"// before\npip install --uploaded-prior-to 2024-01-01 mypkg -i https://internal-simple/\n// after (flag removed)\npip install mypkg -i https://internal-simple/","handlingStrategy":"validation","validationCode":"// Before using --uploaded-prior-to, confirm the index emits upload-time metadata\n// by fetching a simple-index page and checking for the upload-time attribute:\nimport urllib.request, html.parser\nclass T(html.parser.HTMLParser):\n    has_upload = False\n    def handle_starttag(self, tag, attrs):\n        if dict(attrs).get('data-upload-time'):\n            self.has_upload = True\np = T(); p.feed(urllib.request.urlopen(index_url + project + '/').read().decode())\nif not p.has_upload:\n    raise SystemExit('index lacks upload-time metadata; drop --uploaded-prior-to')","typeGuard":null,"tryCatchPattern":"from pip._internal.exceptions import InstallationError\ntry:\n    finder.get_install_candidate(evaluator, link)\nexcept InstallationError as e:\n    if 'upload-time' in str(e):\n        # retry without --uploaded-prior-to or switch index\n        ...","preventionTips":["Verify your index/mirror supports upload-time metadata before adopting --uploaded-prior-to.","Avoid --uploaded-prior-to against plain find-links directories.","In automation, catch InstallationError and degrade gracefully (drop the flag) if the index is unsupported."],"tags":["installation","index","metadata","upload-time"],"backgroundTag":null,"analyzedSha":"f399c3718970b1b0e2478dac5296eb62679a9b86","analyzedAt":"2026-08-08T23:01:42.227Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}