{"record":{"id":"6425e2205ea463ff","repo":"dagger/dagger","slug":"count-lines-of-added-s-w","errorCode":null,"errorMessage":"count lines of added %s: %w","messagePattern":"count lines of added (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/changeset_delta.go","lineNumber":119,"sourceCode":"\t\tif withStats {\n\t\t\tstats, err = compareDirectoriesNumStat(ctx, tmpBefore, tmpAfter)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, nil, fmt.Errorf(\"numstat delta files: %w\", err)\n\t\t\t}\n\t\t}\n\t}\n\n\tif withStats {\n\t\tif stats == nil {\n\t\t\tstats = make(map[string]lineChanges)\n\t\t}\n\t\tif !detectRenames {\n\t\t\t// Added/removed files weren't staged for git; their counts are\n\t\t\t// just the file's own line count.\n\t\t\tfor _, rel := range fc.Added {\n\t\t\t\tlines, ok, err := countGitLines(filepath.Join(afterDir, rel))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, nil, fmt.Errorf(\"count lines of added %s: %w\", rel, err)\n\t\t\t\t}\n\t\t\t\tif ok {\n\t\t\t\t\tstats[rel] = lineChanges{Added: lines}\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor _, rel := range fc.Removed {\n\t\t\t\tlines, ok, err := countGitLines(filepath.Join(beforeDir, rel))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, nil, fmt.Errorf(\"count lines of removed %s: %w\", rel, err)\n\t\t\t\t}\n\t\t\t\tif ok {\n\t\t\t\t\tstats[rel] = lineChanges{Removed: lines}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\trenamedNew := make([]string, 0, len(fc.Renamed))","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/dagger/dagger/blob/82ba2681dbe30d3547a1dc50ea495900ab5b6047/core/changeset_delta.go#L101-L137","documentation":"computeChangesetPathsDelta wraps any failure from countGitLines when counting lines of a newly added file (withStats mode, no rename detection). countGitLines Lstats and reads the added file under afterDir to produce git-numstat-style added line counts, so this error means the added file could not be stat'ed or read at diff time.","triggerScenarios":"Calling computeChangesetPathsDelta with withStats=true when the after tree contains an added file that disappears or becomes unreadable between the metadata walk and the counting pass (concurrent mutation), the path is a broken/dangling special file, or permission bits deny opening it.","commonSituations":"Diffing two mounted snapshot directories while a build concurrently rewrites them; a file deleted by a cleanup step mid-diff; a root-only-readable file in a container layer; overlay/whiteout oddities making a path vanish.","solutions":["Re-run the diff against stable copies of both trees (or re-materialize snapshots) so files do not change mid-walk","Check permissions/ownership on the added file under afterDir and ensure the process can read it","Verify the added path exists on disk after the walk; if the tree mutates concurrently, serialize the diff","If the file is intentionally transient, exclude it from the changeset input before diffing"],"exampleFix":"// before: diffing live mutating dirs directly\nstats, err := computeChangesetPathsDelta(ctx, liveBeforeDir, liveAfterDir, true)\n// after: snapshot/copy dirs first, then diff\nbeforeCopy, afterCopy := snapshotTrees(liveBeforeDir, liveAfterDir)\nstats, err := computeChangesetPathsDelta(ctx, beforeCopy, afterCopy, true)","handlingStrategy":"validation","validationCode":"for _, rel := range fc.Added {\n    p := filepath.Join(afterDir, rel)\n    if fi, err := os.Lstat(p); err != nil || !fi.Mode().IsRegular() {\n        return fmt.Errorf(\"added file unreadable before stats: %s: %w\", p, err)\n    }\n}","typeGuard":"func fileReadable(root, rel string) bool {\n    fi, err := os.Lstat(filepath.Join(root, rel))\n    return err == nil && (fi.Mode().IsRegular() || fi.Mode()&os.ModeSymlink != 0)\n}","tryCatchPattern":"lines, ok, err := countGitLines(p)\nif err != nil {\n    var perr *fs.PathError\n    if errors.As(err, &perr) && errors.Is(perr.Err, fs.ErrNotExist) {\n        continue // file vanished mid-diff; skip or retry\n    }\n    return fmt.Errorf(\"count lines of added %s: %w\", rel, err)\n}","preventionTips":["Diff immutable snapshots, not live directories","Don't delete or prune tree contents while a diff runs","Verify permissions on generated files before diffing","Retry the whole diff on transient IO errors"],"tags":["filesystem","io","line-count"],"backgroundTag":"file-not-found","analyzedSha":"82ba2681dbe30d3547a1dc50ea495900ab5b6047","analyzedAt":"2026-09-05T07:21:37.930Z","contentChangedAt":"2026-09-05T07:21:37.930Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}