# How to Keep a Capped Dependency from Blocking Dependabot Security Updates

A version ceiling in `pyproject.toml` looks like a way to hold Dependabot inside a known-good range. It does not work that way, and which way it fails depends on `versioning-strategy`, a setting most projects never touch. For most projects the failure is not the one the cap was written to prevent.

This page assumes the Dependabot setup in [how to ignore a dependency without blocking its security updates](https://pydevtools.com/handbook/how-to/how-to-ignore-a-dependency-in-dependabot-without-blocking-security-updates.md): a uv project with `uv.lock` committed, and security updates enabled under **Settings → Advanced Security**.

## Drop the cap or raise it

Remove the ceiling and let [uv.lock](https://pydevtools.com/handbook/how-to/how-to-use-a-uv-lockfile-for-reproducible-python-environments.md) hold the exact version. The lockfile is what makes the environment reproducible, so the manifest range does not need to be tight:

```toml {filename="pyproject.toml"}
[project]
dependencies = ["requests>=2.31.0"]
```

Keep the cap only when an upper bound is a real compatibility fact, such as a package that breaks against the next major release. Then [raise the ceiling manually](https://pydevtools.com/handbook/how-to/how-to-upgrade-a-capped-dependency-with-uv.md) whenever an advisory lands above it.

The rest of this page covers what the cap does while it is still there.

## Expect the default strategy to rewrite the ceiling

The default `versioning-strategy` is `auto`, which applies `increase` to applications and `widen` to libraries. Either way Dependabot edits the constraint rather than respecting it. A security update against `requests>=2.31.0,<2.32` in an application moved both bounds:

```diff
-    "requests>=2.31.0,<2.32",
+    "requests>=2.33.0,<2.34",
```

The routine version update on the same project did the same thing, landing on `>=2.34.2,<2.35`. Both paths keep the shape of the constraint and slide it upward, so the ceiling never blocks anything it was written to block.

## Expect lockfile-only to fail silently

Setting `versioning-strategy: lockfile-only` stops the rewrite and replaces it with silence, because the strategy forbids Dependabot from editing the manifest at all. On an identical capped project, Dependabot opened no pull request and failed the job:

```console
INFO Requirements to unlock update_not_possible
INFO The latest possible version of requests that can be installed is 2.33.0
INFO The earliest fixed version is 2.33.0.
| security_update_not_possible |
```

The alert reads "Dependabot cannot update requests to a non-vulnerable version" and never mentions the ceiling that caused it. The same project without the cap got its security pull request.

## Read a doubled alert count as the symptom

A capped manifest raises a second set of alerts against `pyproject.toml` on top of the `uv.lock` ones, so one vulnerable package in a capped project produced six alerts where an uncapped one produced three.

An alert count that jumps for one package without a new advisory is worth checking against a declared range that cannot admit the fixed version.

## Learn More

- [How to Ignore a Dependency in Dependabot Without Blocking Its Security Updates](https://pydevtools.com/handbook/how-to/how-to-ignore-a-dependency-in-dependabot-without-blocking-security-updates.md) covers the matching trap in `ignore` rules.
- [How to Upgrade a Capped Dependency with uv](https://pydevtools.com/handbook/how-to/how-to-upgrade-a-capped-dependency-with-uv.md) walks the manual bump.
- [How to Scan Python Dependencies for Vulnerabilities](https://pydevtools.com/handbook/how-to/how-to-scan-python-dependencies-for-vulnerabilities.md) sets up `uv audit` as a check that does not depend on Dependabot configuration.
- [Dependabot options reference](https://docs.github.com/en/code-security/reference/supply-chain-security/dependabot-options-reference) documents `versioning-strategy`.
