Summary
Since the requirements-layering change in #15521, the Dependabot-powered dependency graph (command: "graph") fails with dependency_file_not_evaluatable on the canonical pip-tools two-layer layout (a requirements.in/requirements.txt pair plus a requirements-dev.in/requirements-dev.txt pair where the dev .in references the prod files). Updater image ghcr.io/dependabot/dependabot-updater-pip:f29b76ff090588b0ecd600aabac344cf9059b6bf (2026-07-10) is broken; 508e93d5854a512864ebac5146581c9a1240074a (2026-07-02) was fine on the identical repo state.
Repro layout
backend/requirements.in # direct prod deps
backend/requirements.txt # pip-compile --generate-hashes lock of the above
backend/requirements-dev.in # "-c requirements.txt" + "-r requirements.in" + test deps
backend/requirements-dev.txt # pip-compile lock of the above
This is the layering workflow from the pip-tools README ("Workflow for layered requirements"), so any repo following it with ≥2 stems in one directory should reproduce.
Error
updater | INFO <job_…> Handled error whilst processing job: dependency_file_not_evaluatable
{message: "InstallationError(\"Could not open constraint file: [Errno 2] No such file or directory: 'dependabot_tmp_dir/requirements.txt'\")"}
Root cause (from reading the code at f29b76f)
Python::DependencyGrapher::RequirementsLayers#files_for_layer builds each layer's manifest group as [primary] + paired-stem files + referenced_requirement_files(primary) + constraints_files, and the transitive -r/-c reference walk is seeded only from the layer's primary file:
- For the dev layer the primary is the compiled
requirements-dev.txt. Compiled locks contain -r/-c only inside # via annotation comments, which the line-anchored SharedFileFetcher::CHILD_REQUIREMENT_REGEX / CONSTRAINT_REGEX (/^-r…/, /^-c…/) correctly don't match — so the walk finds nothing.
- The paired
requirements-dev.in — which holds the real -c requirements.txt and -r requirements.in — is added to the group as a support file but is never scanned for references.
- The
constraints_files fallback only retains files whose basename contains the literal string "constraint", which requirements.txt doesn't.
The group is therefore just [requirements-dev.txt, requirements-dev.in]. Base#build_manifest_group_snapshots (layering activates because there are ≥2 stems/groups) hands a scoped FileParser only those two files; Python::FileParser#parsed_requirement_files writes them into the SharedHelpers temp dir and the helper's parse_requirements() globs *.txt/*.in and runs pip._internal.req.req_file.parse_requirements on each. Parsing requirements-dev.in, pip tries to open the sibling constraint file, raises InstallationError, which REQUIREMENT_FILE_EVALUATION_ERRORS maps to Dependabot::DependencyFileNotEvaluatable.
At 508e93d there was no grouping: the whole directory (all four files) was written to the temp dir together, so the references always resolved.
Note the same failure occurs for the -r requirements.in line as well (the -c just fails first), so the "name your constraint file *constraint*" escape hatch doesn't rescue this layout either.
Suggested fix direction
Seed referenced_requirement_files from every file in the layer group (or at least from the paired .in when the primary is a compiled lock), not just the primary. The .in is precisely where live -r/-c directives are expected to be in a pip-compile workflow.
Why there is no user-side workaround
Moving the -c/-r lines out of requirements-dev.in (into pip-compile CLI flags) makes the graph parse, but breaks Dependabot's own update jobs: PipCompileFileUpdater#pip_compile_options_from_compiled_file reconstructs the compile command from a whitelist of header options that includes neither --constraint nor additional positional source files, so the recompiled dev lock would silently lose the entire prod layer. Layered pip-tools repos are stuck until this is fixed server-side.
Summary
Since the requirements-layering change in #15521, the Dependabot-powered dependency graph (
command: "graph") fails withdependency_file_not_evaluatableon the canonical pip-tools two-layer layout (arequirements.in/requirements.txtpair plus arequirements-dev.in/requirements-dev.txtpair where the dev.inreferences the prod files). Updater imageghcr.io/dependabot/dependabot-updater-pip:f29b76ff090588b0ecd600aabac344cf9059b6bf(2026-07-10) is broken;508e93d5854a512864ebac5146581c9a1240074a(2026-07-02) was fine on the identical repo state.Repro layout
This is the layering workflow from the pip-tools README ("Workflow for layered requirements"), so any repo following it with ≥2 stems in one directory should reproduce.
Error
Root cause (from reading the code at f29b76f)
Python::DependencyGrapher::RequirementsLayers#files_for_layerbuilds each layer's manifest group as[primary] + paired-stem files + referenced_requirement_files(primary) + constraints_files, and the transitive-r/-creference walk is seeded only from the layer's primary file:requirements-dev.txt. Compiled locks contain-r/-conly inside# viaannotation comments, which the line-anchoredSharedFileFetcher::CHILD_REQUIREMENT_REGEX/CONSTRAINT_REGEX(/^-r…/,/^-c…/) correctly don't match — so the walk finds nothing.requirements-dev.in— which holds the real-c requirements.txtand-r requirements.in— is added to the group as a support file but is never scanned for references.constraints_filesfallback only retains files whose basename contains the literal string "constraint", whichrequirements.txtdoesn't.The group is therefore just
[requirements-dev.txt, requirements-dev.in].Base#build_manifest_group_snapshots(layering activates because there are ≥2 stems/groups) hands a scopedFileParseronly those two files;Python::FileParser#parsed_requirement_fileswrites them into theSharedHelperstemp dir and the helper'sparse_requirements()globs*.txt/*.inand runspip._internal.req.req_file.parse_requirementson each. Parsingrequirements-dev.in, pip tries to open the sibling constraint file, raisesInstallationError, whichREQUIREMENT_FILE_EVALUATION_ERRORSmaps toDependabot::DependencyFileNotEvaluatable.At 508e93d there was no grouping: the whole directory (all four files) was written to the temp dir together, so the references always resolved.
Note the same failure occurs for the
-r requirements.inline as well (the-cjust fails first), so the "name your constraint file*constraint*" escape hatch doesn't rescue this layout either.Suggested fix direction
Seed
referenced_requirement_filesfrom every file in the layer group (or at least from the paired.inwhen the primary is a compiled lock), not just the primary. The.inis precisely where live-r/-cdirectives are expected to be in a pip-compile workflow.Why there is no user-side workaround
Moving the
-c/-rlines out ofrequirements-dev.in(into pip-compile CLI flags) makes the graph parse, but breaks Dependabot's own update jobs:PipCompileFileUpdater#pip_compile_options_from_compiled_filereconstructs the compile command from a whitelist of header options that includes neither--constraintnor additional positional source files, so the recompiled dev lock would silently lose the entire prod layer. Layered pip-tools repos are stuck until this is fixed server-side.