Skip to content

Grouped go_modules updates drop deletions of vendored files (regression from #16290) #16527

Open

Description

@huww98

Is there an existing issue for this?

  • I have searched the existing issues

Package ecosystem

go_modules

Package manager version

Go (as bundled in the Dependabot updater image, run of 2026-10-01)

Language version

go 1.26.0 (go.mod)

Manifest location and content before the Dependabot update

/go.mod with a committed vendor/ directory: https://github.com/kubernetes-sigs/alibaba-cloud-csi-driver/blob/d340dba7bbd8e3319b16c80e822ecaa7901d2c7c/go.mod

dependabot.yml content

version: 2
updates:
  - package-ecosystem: gomod
    directory: /
    open-pull-requests-limit: 10
    schedule:
      interval: monthly
    groups:
      security:
        applies-to: security-updates
        patterns:
          - "*"
      k8s:
        patterns:
          - k8s.io/api
          - k8s.io/apimachinery
          - k8s.io/client-go
          - k8s.io/component-base
          - k8s.io/kubelet
          - k8s.io/mount-utils

Updated dependency

k8s group: k8s.io/apimachinery, k8s.io/client-go, k8s.io/component-base, k8s.io/kubelet, k8s.io/mount-utils from 0.36.2 to 0.37.1 (which also bumps go-openapi/swag 0.23 → 0.27, kube-openapi, etc.).

What you expected to see, versus what you actually saw

Expected: the PR commit matches go get … && go mod tidy && go mod vendor, including deletions of vendored files that are no longer needed.

Actual: grouped PR kubernetes-sigs/alibaba-cloud-csi-driver#1838 adds and modifies vendored files but deletes none. 83 stale files remain in vendor/, so the build breaks:

vendor/github.com/go-openapi/swag/convert.go:31:6: IsFloat64AJSONInteger redeclared in this block
vendor/k8s.io/api/extensions/v1beta1/zz_generated.validations.go:128:33: undefined: validate.EachSliceVal

Running go mod tidy && go mod vendor on the PR branch produces only those 83 deletions (go.mod, go.sum, vendor/modules.txt are unchanged), so the version resolution is fine; only the deletions are lost.

This is a regression. The PR was regenerated several times, and the older head commits are still fetchable:

head commit date added modified deleted renamed
b482d47e9 2026-09-03 294 958 45 38
bbe238c4f 2026-09-18 332 958 0 0
11e9b00c4 2026-09-21 332 922 0 0
2c15fbb80 2026-10-01 332 922 0 0

Earlier grouped PRs in the same repo also contained vendored deletions (e.g. kubernetes-sigs/alibaba-cloud-csi-driver#1465, 24 removed files).

Suspected cause

The job source uses directories ("source":{…,"directories":["/"]} in the job definition), so since #16290 (merged 2026-09-16) both create and refresh go through compile_all_dependency_changes_for_directories, which passes every changed file through apply_file_change:

def apply_file_change(file, working_files_by_path, changed_files_by_path, initial_paths, created_paths)
if file.deleted?
working_files_by_path.delete(file.path)
created_paths.delete(file.path)
if initial_paths.include?(file.path)
changed_files_by_path[file.path] =
file
else
changed_files_by_path.delete(file.path)
end
return
end

initial_paths is built from dependency_snapshot.all_dependency_files (L192-L197), i.e. only the fetched manifests (go.mod, go.sum). Vendored files are never in it, so every vendored DELETE is treated as "created during this group, then deleted" and silently dropped. Vendored files that are modified are similarly re-labelled CREATE instead of UPDATE, which happens to be harmless because their content is sent in full.

Up to that point the deletions are tracked correctly: VendorUpdater reports them from git status and DependencyGroupChangeBatch keeps them as DELETE. #16314 addressed the same "vendored paths aren't in the initial set" gap inside DependencyGroupChangeBatch, but apply_file_change still relies on initial_paths.

Possible fix: for files not in initial_paths, decide based on whether the path exists in the base commit (or keep the operation computed by DependencyGroupChangeBatch, which already tracks initially_exists per path), instead of assuming they were created during the group.

This likely affects any grouped update with vendored files (go_modules vendor/, bundler vendor/cache, …) whose job source uses directories. Note our config only sets directory: /, yet the job arrives with directories: ["/"].

Native package manager behavior

go get k8s.io/apimachinery@v0.37.1 k8s.io/client-go@v0.37.1 k8s.io/component-base@v0.37.1 k8s.io/kubelet@v0.37.1 k8s.io/mount-utils@v0.37.1 && go mod tidy && go mod vendor yields the same go.mod/go.sum/vendor/ as the Dependabot PR plus 83 deleted files under vendor/ (e.g. vendor/github.com/go-openapi/swag/{convert,json,util,...}.go, vendor/github.com/mailru/easyjson/**, vendor/github.com/josharian/intern/**, vendor/k8s.io/api/apidiscovery/v2beta1/**, vendor/k8s.io/api/scheduling/v1alpha2/**, vendor/k8s.io/api/extensions/v1beta1/zz_generated.validations.go). Manually fixed version: kubernetes-sigs/alibaba-cloud-csi-driver#1868

Images of the diff or a link to the PR, issue, or logs

Smallest manifest that reproduces the issue

Any Go module with a committed vendor/ directory, a grouped update configured via directories (or directory, if it is normalized to directories), where one of the bumps makes go mod vendor remove a previously vendored file.

Activity

  1. huww98 commented on Oct 10, 2026

    @huww98
    Author

    I confirmed this locally with the dependabot CLI and the current dependabot-updater-gomod image (its updater/lib and common/lib are identical to main at 4725d25), by mounting a git revert of #16290 over updater/lib for the B side.

    Minimal reproduction

    https://github.com/huww98/dependabot-vendor-delete-repro (runs in ~1 minute): a module vendoring github.com/cespare/xxhash/v2 v2.1.2, a single all group, and a job.yml with directories: [/]. Upgrading to v2.3.0 makes go mod vendor delete vendor/github.com/cespare/xxhash/v2/xxhash_amd64.go.

    updated-dependency-files in the create_pull_request payload:

    main main with #16290 reverted main, job uses directory: /
    delete xxhash_amd64.go ❌ missing ✅ ✅
    existing vendored files (xxhash.go, modules.txt, …) create update update
    new vendored files (xxhash_asm.go, …) create create create

    The lost deletion leaves a stale file that breaks the build:

    vendor/github.com/cespare/xxhash/v2/xxhash_asm.go:12:6: Sum64 redeclared in this block
    	vendor/github.com/cespare/xxhash/v2/xxhash_amd64.go:10:6: other declaration of Sum64
    

    Original job

    Replaying the job definition from the original run (pinned to the same base commit) gives the same result at scale. The vendored file operations:

    delete create update
    main 0 1252 0
    main with #16290 reverted 83 332 920
    manual go get … && go mod tidy && go mod vendor 83 332 920

    With the revert, the delete/create/update file lists and contents match the manual result exactly.

    Side note for anyone replaying a real job definition with the CLI: GitHub enables the blocked-versions experiment, and dependabot CLI v1.94.0 doesn't serve the GET …/blocked_versions endpoint, so the job aborts with Malformed blocked versions response unless the CLI's fake API is patched to answer {"data":[]}. The minimal repro doesn't enable it and works with the stock CLI.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions