dagger/dagger · error

verify modified file: %w

Error message

verify modified file: %w

What it means

changesetDeltaIsEmpty wraps errors from modifiedFileDiffers for each metadata-suspect candidate with 'verify modified file'. It means content/mode verification of a specific modified file failed — a stat or readlink error (errors 344–347) bubbled up during the emptiness check.

Source

Thrown at core/changeset_delta.go:334

// (e.g. an added empty dir) don't. Added or removed files prove the changeset
// non-empty regardless of how git would pair them into renames, and
// metadata-suspect files are verified by content with an early exit on the
// first real difference.
func changesetDeltaIsEmpty(ctx context.Context, beforeDir, afterDir string) (bool, error) {
	delta, err := collectChangesetDelta(ctx, beforeDir, afterDir)
	if err != nil {
		return false, fmt.Errorf("collect delta: %w", err)
	}
	if len(delta.addedFiles) > 0 || len(delta.removedFiles) > 0 {
		return false, nil
	}
	for _, rel := range delta.modifiedCandidates {
		if err := ctx.Err(); err != nil {
			return false, context.Cause(ctx)
		}
		changed, err := modifiedFileDiffers(beforeDir, afterDir, rel)
		if err != nil {
			return false, fmt.Errorf("verify modified file: %w", err)
		}
		if changed {
			return false, nil
		}
	}
	return true, nil
}

// gitFileMode maps a file's mode onto the modes git tracks: symlink, and
// executable vs regular file. Other permission bits are invisible to git.
func gitFileMode(fi os.FileInfo) uint32 {
	if fi.Mode()&os.ModeSymlink != 0 {
		return 0o120000
	}
	if fi.Mode()&0o111 != 0 {
		return 0o100755
	}
	return 0o100644

View on GitHub (pinned to 82ba2681db)

Solutions

  1. Read the wrapped error to identify the failing file and fix its cause (permissions, deletion)
  2. Re-run the check with both trees stable/frozen
  3. Stop concurrent writers (builds, formatters) during the diff
  4. If caused by a genuinely missing file, re-materialize the snapshot

Example fix

// before: gofmt -w running while emptiness is checked
exec.Command("gofmt", "-w", dir).Start()
empty, err := changesetDeltaIsEmpty(ctx, beforeDir, afterDir)
// after: format first, then check
exec.Command("gofmt", "-w", dir).Run()
empty, err := changesetDeltaIsEmpty(ctx, beforeDir, afterDir)
Defensive patterns

Strategy: try-catch

Validate before calling

if _, err := os.Lstat(filepath.Join(beforeDir, rel)); err != nil {
    return fmt.Errorf("candidate before side gone: %w", err)
}
if _, err := os.Lstat(filepath.Join(afterDir, rel)); err != nil {
    return fmt.Errorf("candidate after side gone: %w", err)
}

Type guard

func verifiable(rootA, rootB, rel string) bool {
    _, e1 := os.Lstat(filepath.Join(rootA, rel))
    _, e2 := os.Lstat(filepath.Join(rootB, rel))
    return e1 == nil && e2 == nil
}

Try / catch

empty, err := changesetDeltaIsEmpty(ctx, beforeDir, afterDir)
if err != nil {
    if errors.Is(err, fs.ErrNotExist) {
        return false, nil // a candidate changed mid-check: not empty
    }
    return false, fmt.Errorf("verify modified file: %w", err)
}

Prevention

When it happens

Trigger: A modified candidate's file vanishes or becomes unreadable between the metadata walk and the content verification loop in changesetDeltaIsEmpty — races with writers mutating either tree mid-check.

Common situations: Editors, build daemons, or codegen touching files while an emptiness check runs; cache layers being evicted; permission changes applied concurrently.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of dagger/dagger@82ba2681db (2026-09-05). Data as JSON: /api/errors/45e03ded5dcdbc08. Report an issue: GitHub.