Constraint provenance¶
Part of Explanation.
A constraint says more than which version is installed. It says who has the power to change it. OSS IQ reports where each constraint comes from, so you see that before a CVE forces you to find out.
What holds the version |
Who can change it |
|---|---|
A range in your manifest |
You |
A constraints file, or uv’s |
Whoever owns that file or setting |
An override |
Whoever wrote the override |
A range another package declares on a transitive dependency |
That package’s maintainers |
The five constraint types, and how OSS IQ reads each package manager’s settings, are in Reference → Constraints, overrides and aliases.
Why a constraint is harder to fix than a dependency¶
When a normal dependency becomes vulnerable, the fix is direct: update it, and the resolver picks a patched version.
Constraints and overrides break that flow, because they impose version rules from outside the
normal dependency graph. A constraint can hold a transitive package in a range that still
contains a vulnerable version, and nothing in the lockfile shows it. You can read h11==0.13.0
in the lockfile and have no idea that a rule somewhere else stops 0.14.0 from resolving.
Against Upper-Bound Version Constraints in Libraries
describes this failure mode. Once a constraint caps a package below a patched version, you
cannot fix it alone: the person who wrote the constraint has to release a patch first. With many
transitive constraints spread across pyproject.toml entries and nested overrides, the debt
stays invisible until a CVE forces a full audit.
Why overrides and constraints are tracked separately¶
An OVERRIDE means someone decided that a package’s own version declarations don’t matter. An
ADDITIVE constraint means a separate authority narrows what the resolver can pick. Neither is
an ordinary declared dependency, so OSS IQ reports both apart from those.
constraint_info names which packages are under a constraint, what kind it is, and which file
introduced it.
Why a newer version can stay out of reach¶
Sometimes a direct dependency cannot move forward even though a newer version exists. A direct dependency is one node in a graph. Each of its versions declares its own requirements on transitive packages, and other parents in your tree constrain those same packages. The solver recommends a version only when the whole subtree still resolves.
Take a project that depends on A and B. A 2.0 requires C >= 3, but the latest B still
requires C < 3. No version of C satisfies both, so A cannot reach 2.0:
The report shows |
It means |
|---|---|
A newer Latest, a Recommended that stays behind, and a |
The update to |
|
Every candidate version of |
|
The constraints already contradict each other in the current tree, before any update |
The owner of the blocking constraint, here B, has to publish a release that widens its range.
For what you can do in the meantime, see
Move past a transitive constraint.