{"record":{"id":"47c0d3546b88b79b","repo":"gastownhall/beads","slug":"refusing-to-chmod-s-path-is-not-a-directory","errorCode":null,"errorMessage":"refusing to chmod %s: path is not a directory","messagePattern":"refusing to chmod (.+?): path is not a directory","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/config/permissions.go","lineNumber":60,"sourceCode":"type beadsDirHandle interface {\n\tStat() (os.FileInfo, error)\n\tChmod(os.FileMode) error\n\tClose() error\n}\n\nfunc fixBeadsDirPermissions(path string, openDir func(string) (beadsDirHandle, error)) (bool, error) {\n\tinfo, err := os.Lstat(path)\n\tif err != nil {\n\t\tif os.IsNotExist(err) {\n\t\t\treturn false, nil // directory doesn't exist yet\n\t\t}\n\t\treturn false, fmt.Errorf(\"failed to inspect %s: %w\", path, err)\n\t}\n\tif info.Mode()&os.ModeSymlink != 0 {\n\t\treturn false, fmt.Errorf(\"refusing to chmod %s: path is a symbolic link\", path)\n\t}\n\tif !info.IsDir() {\n\t\treturn false, fmt.Errorf(\"refusing to chmod %s: path is not a directory\", path)\n\t}\n\tperm := info.Mode().Perm()\n\tif perm&0077 == 0 {\n\t\treturn false, nil // no group or world-accessible bits\n\t}\n\n\tdir, err := openDir(path)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"failed to open %s securely: %w\", path, err)\n\t}\n\tdefer func() { _ = dir.Close() }()\n\n\topenedInfo, err := dir.Stat()\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"failed to inspect opened directory %s: %w\", path, err)\n\t}\n\tif !openedInfo.IsDir() || !os.SameFile(info, openedInfo) {\n\t\treturn false, fmt.Errorf(\"refusing to chmod %s: path changed during permission repair\", path)","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/config/permissions.go#L42-L78","documentation":"fixBeadsDirPermissions refuses to chmod the path because os.Lstat shows it is not a directory (e.g. a regular file named .beads). chmod-ing a non-directory to 0700 would be meaningless for the intended directory-permission repair, so the call fails instead.","triggerScenarios":"Calling FixBeadsDirPermissions(path) where path exists but info.IsDir() is false — typically a regular file, fifo, or device node occupying the .beads path.","commonSituations":"A stray file named .beads was created accidentally (e.g. output redirection like `> .beads`); a failed init left a file where the directory should be; a sync tool replaced the directory with a file.","solutions":["Check what is at the path with ls -la .beads.","Remove or rename the non-directory entry (e.g. mv .beads .beads.bak).","Recreate the directory with mkdir -m 700 .beads and re-run the operation.","If the file contains data, inspect it before deleting — it may be a mislocated database file."],"exampleFix":"// before: .beads is a regular file\n// after\n$ mv .beads .beads.file.bak\n$ mkdir -m 700 .beads","handlingStrategy":"validation","validationCode":"info, err := os.Stat(beadsDir)\nif err == nil && !info.IsDir() {\n    return fmt.Errorf(\"%s exists but is not a directory; move it aside and run bd init\", beadsDir)\n}","typeGuard":"func isDirectory(path string) bool {\n    info, err := os.Stat(path)\n    return err == nil && info.IsDir()\n}","tryCatchPattern":null,"preventionTips":["Avoid shell redirections that could create a file named .beads.","After failed init/restore operations, verify the path type before retrying.","Use `bd init` to create the directory rather than manual mkdir with odd names."],"tags":["permissions","filesystem","directory"],"backgroundTag":"path-not-a-directory","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}