{"record":{"id":"0387a9c631ae63f7","repo":"docker/compose","slug":"finding-ancestor-of-s-w","errorCode":null,"errorMessage":"finding ancestor of %s: %w","messagePattern":"finding ancestor of (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/watch/watcher_naive.go","lineNumber":348,"sourceCode":"\t\twatcher:            fsw,\n\t\tevents:             fsw.Events,\n\t\twrappedEvents:      wrappedEvents,\n\t\terrors:             fsw.Errors,\n\t\tisWatcherRecursive: isWatcherRecursive,\n\t}\n\twmw.addWatch = wmw.add\n\n\treturn wmw, nil\n}\n\nvar _ Notify = &naiveNotify{}\n\nfunc greatestExistingAncestors(paths []string) ([]string, error) {\n\tresult := []string{}\n\tfor _, p := range paths {\n\t\tnewP, err := greatestExistingAncestor(p)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"finding ancestor of %s: %w\", p, err)\n\t\t}\n\t\tresult = append(result, newP)\n\t}\n\treturn result, nil\n}\n","sourceCodeStart":330,"sourceCodeEnd":354,"githubUrl":"https://github.com/docker/compose/blob/ddc4b044b62e9f715212ea4143fa830fac76382f/pkg/watch/watcher_naive.go#L330-L354","documentation":"This error is thrown by Docker Compose's file watcher (docker compose watch / up --watch) when it cannot resolve a watch path to an existing directory. Before subscribing to filesystem events, the naive (fsnotify-based) watcher walks each configured path upward through its ancestors to find the closest one that exists, so it can watch that ancestor and detect when the missing path is later created. If that walk fails for any path, the wrapped cause is reported with this message. The two underlying causes produced by greatestExistingAncestor (pkg/watch/paths.go:25) are 'cannot watch root directory' — the walk reached / or a Windows volume root without finding an existing ancestor — and an os.Stat failure other than not-exist (e.g. permission denied, I/O error) on the path or one of its parents.","triggerScenarios":"Running 'docker compose watch' or 'docker compose up --watch' where a develop.watch path (regular expression or explicit path in the compose file's develop section, or a bind-mount source without a corresponding host directory) resolves to / , a Windows drive root like C:\\, or a path whose entire ancestor chain does not exist (e.g. /nonexistent/deeply/nested/dir on a fresh checkout). Also triggered when os.Stat on the path or an ancestor fails with EACCES/EPERM (unreadable parent directory) or an I/O error, for example when the project lives on a network mount, a FUSE volume, or a directory with restrictive permissions.","commonSituations":"A develop.watch path pointing to a directory that was never created or is gitignored and missing after clone; a path typo so no ancestor matches anything real; a path anchored at the filesystem root; running the watcher against a container path instead of the host path; home-directory expansion (~) not expanded so the literal '~' directory does not exist; permission-restricted environments (root-squashed NFS, SELinux denials) where stat on a parent fails; CI environments where expected volumes are not mounted.","solutions":["Check the failing path (named in the error message after 'ancestor of') against your compose file's develop section and bind-mount sources; fix typos or create the missing directory with mkdir -p.","Ensure watch paths are host-side absolute or correctly relative paths, not container-internal paths, and that '~' is expanded to $HOME before being handed to compose.","Never configure / (or a bare Windows drive like C:\\) as a watch path — the watcher explicitly refuses to watch the root directory; narrow it to a project subdirectory.","If the cause is a stat error such as permission denied, fix filesystem permissions on the path and its parents (or remount the network volume) and confirm with 'stat <path>' as the same user that runs compose.","Re-run docker compose watch and confirm the error is gone; use docker compose config to render the resolved develop section and verify the paths."],"exampleFix":"// docker-compose.yml — before\ndevelop:\n  watch:\n    - action: sync\n      path: ./src\n      target: /app/src\n// error: finding ancestor of /proj/src: cannot watch root directory\n// (./src does not exist on host, so ancestor walk reached /)\n\n// after — create the watched host directory, or point at one that exists\nmkdir -p ./src\ndocker compose watch","handlingStrategy":"validation","validationCode":"// Before starting docker compose watch, verify each watch path\n// has at least one existing ancestor and is not a filesystem root.\nfunc validateWatchPath(path string) error {\n    abs, err := filepath.Abs(path)\n    if err != nil {\n        return fmt.Errorf(\"resolving %s: %w\", path, err)\n    }\n    if abs == string(filepath.Separator) || abs == filepath.VolumeName(abs)+string(filepath.Separator) {\n        return fmt.Errorf(\"%s is a filesystem root; cannot be watched\", abs)\n    }\n    for p := abs; ; p = filepath.Dir(p) {\n        if _, err := os.Stat(p); err == nil {\n            return nil // found an existing ancestor\n        } else if !os.IsNotExist(err) {\n            return fmt.Errorf(\"stat %q: %w\", p, err) // permission/IO problem\n        }\n        if p == filepath.Dir(p) {\n            return fmt.Errorf(\"no existing ancestor of %s\", abs)\n        }\n    }\n}","typeGuard":"// Go callers of docker/compose/v5/pkg/watch directly:\ntype rootWatchError struct{ path string }\nfunc (e rootWatchError) Error() string { return \"cannot watch root directory\" }\n\n// errors.As / errors.Is cannot match the anonymous fmt.Errorf in\n// greatestExistingAncestor, so match on the wrapped text instead:\nfunc isWatchAncestorError(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"finding ancestor of \")\n}","tryCatchPattern":"// In Go, treat watcher startup as fatal but report the offending path:\nif err := watcher.Start(); err != nil {\n    var pathErr *fs.PathError\n    if errors.As(err, &pathErr) && os.IsPermission(pathErr.Err) {\n        log.Fatalf(\"watch: fix permissions on %s: %v\", pathErr.Path, err)\n    }\n    if strings.Contains(err.Error(), \"cannot watch root directory\") {\n    log.Fatalf(\"watch: refusing to watch filesystem root; narrow the develop.watch path\")\n    }\n    log.Fatalf(\"watch: %v\", err)\n}","preventionTips":["Keep every develop.watch path inside the project directory and commit (or mkdir at setup) the watched directories so a fresh clone always has them.","Run 'docker compose config' to render the resolved develop section and confirm each path is a real host path before invoking watch.","Expand ~ and environment variables in watch paths yourself; compose does not create missing host directories for you.","Never use / or a bare drive letter as a watch root; choose the deepest directory that actually exists.","On network/permission-sensitive mounts, verify 'stat <path>' succeeds as the compose user before starting watch."],"tags":["docker-compose","file-watching","fsnotify","filesystem","configuration"],"backgroundTag":null,"analyzedSha":"ddc4b044b62e9f715212ea4143fa830fac76382f","analyzedAt":"2026-08-15T13:31:42.319Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}