Repository navigation
uv: versioning-strategy: lockfile-only blocks security updates for transitive dependencies (security_update_not_possible) #16449
Description
Is there an existing issue for this?
- I have searched the existing issues
Related but distinct: #16112 (uv drops versioning-strategy values other than lockfile-only).
Package ecosystem
uv
Package manager version
uv 0.12.18 (Dependabot's bundled uv)
Language version
Python 3.12.13
Manifest location and content before the Dependabot update
/pyproject.toml and /uv.lock. The vulnerable package, urllib3, is transitive only: it isn't listed in pyproject.toml, and it comes in via botocore and requests. uv.lock had urllib3 2.7.0.
[project]
name = "example-app"
requires-python = ">=3.12"
dependencies = [
"pulumi-aws>=7.32.0,<8", # -> boto3/botocore -> urllib3
]
[tool.uv]
package = falsedependabot.yml content
version: 2
updates:
- package-ecosystem: "uv"
directory: "/"
schedule:
interval: "monthly"
versioning-strategy: lockfile-only
groups:
all:
patterns: ["*"]
ignore:
- dependency-name: "*"
update-types: ["version-update:semver-major"]Updated dependency
urllib3 2.7.0 → 2.8.0 (security update; every open advisory affects < 2.8.0)
What you expected to see, versus what you actually saw
Expected: a security update PR changing only uv.lock. The versioning-strategy docs say lockfile-only will "Only create pull requests to update lockfiles. Ignore any new versions that would require package manifest changes". This fix needs no manifest change. The security updates docs say the only transitive dependencies Dependabot can't update are those that would also need an update to the parent; here neither parent needs one.
Actual: the job fails with security_update_not_possible. The error itself reports the target as resolvable:
| security_update_not_possible | { |
| | "dependency-name": "urllib3", |
| | "latest-resolvable-version": "2.8.0", |
| | "lowest-non-vulnerable-version": "2.8.0", |
| | "conflicting-dependencies": [] |
| | } |
The log shows the decision is made before any resolution runs. uv lock is only invoked afterwards, to fill in the error details:
14:00:37 INFO Latest version is 2.8.0
14:00:37 INFO Requirements to unlock update_not_possible
...
14:00:40 INFO Running command: pyenv exec uv lock --upgrade-package urllib3==2.8.0 --index <private index>
14:00:43 INFO Process PID: 1937 completed with status: pid 1937 exit 0
14:00:44 INFO The latest possible version of urllib3 that can be installed is 2.8.0
Cause, as far as we can trace it (permalinks at d8bfe06c):
CreateSecurityUpdatePullRequest#requirements_to_unlocktries onlycan_update?(requirements_to_unlock: :none)whenrequirements_unlocked_or_can_be?is false.- For Python/uv,
requirements_unlocked_or_can_be?is!requirements_update_strategy.lockfile_only?, so it is false underlockfile-only. :nonecallslatest_resolvable_version_with_no_unlock, which callsresolver.latest_resolvable_version(requirement: current_requirement_string).- A sub-dependency has no requirements, so
current_requirement_stringisnil.LockFileResolver#latest_resolvable_versionstarts withreturn nil unless requirement, socan_update?(:none)is false and the result is:update_not_possible.
So under lockfile-only, every uv security update for a transitive dependency fails this way, whatever the dependency graph looks like. Lockfile-only is arguably the case where these updates matter most, since the lockfile is the only thing that can change.
Confirmation: changing only versioning-strategy to increase-if-necessary made the next security job on the same commit graph succeed. Its job spec then carried "requirements-update-strategy":null and "lockfile-only":false (see #16112). It logged Requirements to unlock own, then Updating urllib3 from 2.7.0 to 2.8.0, and opened a PR touching only uv.lock. A security update for urllib3 2.6.3 → 2.7.0 in May, before we set lockfile-only, also succeeded.
Native package manager behavior
uv lock --upgrade-package urllib3==2.8.0 on the same pyproject.toml/uv.lock succeeds and changes only uv.lock:
Resolved 58 packages in 4.42s
Updated urllib3 v2.7.0 -> v2.8.0
Images of the diff or a link to the PR, issue, or logs
The repository is private, so the job logs aren't public. The excerpts above are from the failing job (job_1602853618) and the succeeding job (job_1602897949). We can share more of the log on request.
Smallest manifest that reproduces the issue
Any uv project with a vulnerable transitive-only dependency pinned in uv.lock, where the fixed version is compatible with the parents, and versioning-strategy: lockfile-only set. The manifest above is enough.
Metadata
Metadata
Assignees
Type
Projects
- StatusShow more project fieldsNo status
Activity
jspiewak commentedon Oct 2, 2026
We're hitting the same failure in a second private repository. This one is a library (
package = true, built with setuptools), unlike the application in the original report (package = false).urllib3is again transitive only (pulumi-kubernetes→requests→urllib3), locked at 2.7.0, anduv lock --upgrade-package urllib3resolves 2.8.0 cleanly, changing onlyuv.lock.The job spec has
"lockfile-only":true,"allowed-updates":[{"dependency-type":"direct","update-type":"all"}], and"update-subdependencies":false, and the log shows the same early decision:Unlike the original report, this job didn't run
uv lockafterwards to fill in thesecurity_update_not_possibledetails. It finished right afterNo update possible.For libraries, the workaround from the original report (switching to
increase-if-necessary) isn't really available. We setlockfile-onlybecause of #14908: the other strategies raise lower bounds inpyproject.toml, and in a library those bounds are the minimum versions consumers get. So a library that uses uv currently has to choose between receiving transitive security updates and keeping its declared lower bounds stable. For now we're applying these fixes by hand.Add a weekly workflow that refreshes uv.lock
Bump virtualenv to 21.14.5 to fix 4 Dependabot alerts (#630)