Skip to content

uv dependency updates cannot resolve: modal and otel extras pin incompatible protobuf #4088

Description

@chernistry

The weekly uv update job fails outright and lands no PR. From the run on 73b3c43e:

Handled error whilst updating protobuf: dependency_file_not_resolvable

Because modal>=1.4.2 depends on one of:
    protobuf>=3.19,<4.24.0
    protobuf>4.24.0,<7.0
and opentelemetry-proto>=1.44.0 depends on protobuf==7.35.1, we
can conclude that modal>=1.4.2 and opentelemetry-proto>=1.44.0 are
incompatible.
...
And because bernstein[otel] depends on
opentelemetry-exporter-otlp-proto-grpc>=1.41.1 and bernstein[modal]
depends on modal>=1.4.2, we can conclude that bernstein[modal] and
bernstein[otel] are incompatible.
And because your project requires bernstein[modal] and bernstein[otel],
we can conclude that your project's requirements are unsatisfiable.

opentelemetry-proto pins protobuf==7.35.1 from 1.41.1 onward; modal caps it below 7.0. There is no version of protobuf that satisfies both, so [modal] and [otel] cannot resolve together.

pyproject.toml already declares one such pair — uv sync --all-extras refuses with "Extras grpc and modal are incompatible with the declared conflicts". modal × otel is the same shape and is not declared, so instead of being a known-incompatible pair it reads to the resolver as an unsatisfiable project.

What makes this worth fixing ahead of its size: the updater aborts the whole job on that error, so no uv dependency update lands at all — not a grouped minor bump and not a security bump either. The last one to get through was the group on #4080, and only because it predates the protobuf attempt. A supply-chain gate nobody can push through is off, not strict.

Where to start

pyproject.toml — the [[tool.uv.conflicts]] entries (the grpc × modal pair is the pattern to follow) and the otel / modal optional-dependency groups. The failing job is .github/workflows/dependabot-updates runs under the uv ecosystem in .github/dependabot.yml.

What proves it

uv lock --check resolving after the change, and uv sync --extra modal / uv sync --extra otel each succeeding on their own. A declared conflict has to still let both extras be installed separately — the failure mode of a careless fix is declaring the conflict so broadly that one of them stops installing.

Then a test that pins the pair, in the module that already covers the extras layout, so a future extra that reintroduces the same protobuf clash fails in the suite rather than three weeks later in a dependabot log nobody reads. Name it for the property: something like test_conflicting_extras_are_declared_not_merely_unsatisfiable.

Out of scope

Do not resolve it by capping opentelemetry-* — the otel exporters are on a security-relevant upgrade path and pinning them back to keep modal happy trades the wrong thing. Do not drop either extra.

The decision that is yours

Whether modal and otel are genuinely mutually exclusive for our users, or whether modal should move to a vendored/subprocess boundary so the protobuf pin stops being shared at all. Declaring the conflict is the small correct fix and unblocks the updater today; the second answer is a larger change and would want its own issue. Say which one you took in the PR body.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingcidependenciesPull requests that update a dependency filesize/sup-for-grabsListed on up-for-grabs.net — no commitment, low friction

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions