{"record":{"id":"500668849819a35d","repo":"dagger/dagger","slug":"path-modified-in-one-changeset-and-removed-in-the","errorCode":null,"errorMessage":"path modified in one changeset and removed in the other","messagePattern":"path modified in one changeset and removed in the other","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/changeset.go","lineNumber":898,"sourceCode":"type ChangeType int\n\nconst (\n\tChangeTypeAdded ChangeType = iota\n\tChangeTypeModified\n\tChangeTypeRemoved\n)\n\ntype Conflict struct {\n\tPath  string\n\tSelf  ChangeType\n\tOther ChangeType\n\tErr   error\n}\n\nvar (\n\tErrAddedTwice      = errors.New(\"path added in both changesets\")\n\tErrModifiedTwice   = errors.New(\"path modified in both changesets\")\n\tErrModifiedRemoved = errors.New(\"path modified in one changeset and removed in the other\")\n)\n\ntype Conflicts []Conflict\n\nfunc (conflicts Conflicts) Error() (err error) {\n\tfor _, c := range conflicts {\n\t\terr = errors.Join(err, fmt.Errorf(\"conflict between changesets at path %q: %w\", c.Path, c.Err))\n\t}\n\treturn err\n}\n\nfunc (conflicts Conflicts) IsEmpty() bool {\n\treturn len(conflicts) == 0\n}\n\nfunc (conflicts Conflicts) ModifyDeletePaths() []string {\n\tvar paths []string\n\tfor _, c := range conflicts {","sourceCodeStart":880,"sourceCodeEnd":916,"githubUrl":"https://github.com/dagger/dagger/blob/82ba2681dbe30d3547a1dc50ea495900ab5b6047/core/changeset.go#L880-L916","documentation":"ErrModifiedRemoved is a sentinel error returned when one changeset modifies a path while the other removes it. This modify/delete conflict is unreconcilable automatically, so the merge fails with a conflict entry; the path is also called out specially in the aggregate message (Conflicts.Error groups these paths).","triggerScenarios":"Merging changesets where one has ChangeTypeModified and the other ChangeTypeRemoved for the same path (core/changeset.go:965); detected in Conflicts.Error's special-case formatting at core/changeset.go:917.","commonSituations":"One session edited a file while another (or the base snapshot) deleted it; stale changesets replayed after files were removed; parallel refactors where one branch deletes a file another updates.","solutions":["Decide whether the file should exist: drop the modification from the surviving changeset, or re-add the file in the deleting one.","Rebase one changeset onto the other so the delete supersedes (or incorporates) the modification.","Use errors.Is(err, ErrModifiedRemoved) to find affected paths via the Conflicts list and resolve each explicitly.","Rebuild a single changeset reflecting the intended final state of the path."],"exampleFix":"// before\nmerged, err := cs1.Merge(cs2) // fails: modified in one, removed in other\n// after\nif conflicts, ok := err.(changeset.Conflicts); ok {\n    for _, c := range conflicts {\n        if errors.Is(c.Err, changeset.ErrModifiedRemoved) {\n            // choose: keep the delete\n            cs1 = cs1.WithoutPath(c.Path)\n        }\n    }\n    merged, err = cs1.Merge(cs2)\n}","handlingStrategy":"type-guard","validationCode":"// detect modify/delete pairs before merge\nremoved, modified := map[string]bool{}, map[string]bool{}\nfor _, c := range cs1.Changes() { (map[core.ChangeType]func(){...}) } // collect Removed into removed, Modified into modified\n// conflict if removed[p] && modified[p] for any p","typeGuard":"func isModifiedRemoved(err error) bool { return errors.Is(err, core.ErrModifiedRemoved) }","tryCatchPattern":"if err := cs1.Merge(cs2); err != nil {\n    if errors.Is(err, core.ErrModifiedRemoved) {\n        // decide keep-vs-delete for the reported paths and rebuild one changeset\n    }\n    return err\n}","preventionTips":["Decide file lifecycle (keep or delete) before parallel edits.","Rebase deletions against later modifications and vice versa.","List Removed paths in one changeset and Modified in the other before merging."],"tags":["dagger","changeset","merge-conflict","modify-delete","sentinel-error"],"backgroundTag":"changeset-merge-conflict","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"}