{"record":{"id":"d243dd32b235593d","repo":"charmbracelet/crush","slug":"failed-to-create-data-directory-q-w","errorCode":null,"errorMessage":"failed to create data directory: %q %w","messagePattern":"failed to create data directory: %q %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/util.go","lineNumber":11,"sourceCode":"package backend\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\nfunc createDotCrushDir(dir string) error {\n\tif err := os.MkdirAll(dir, 0o700); err != nil {\n\t\treturn fmt.Errorf(\"failed to create data directory: %q %w\", dir, err)\n\t}\n\n\tgitIgnorePath := filepath.Join(dir, \".gitignore\")\n\tif _, err := os.Stat(gitIgnorePath); os.IsNotExist(err) {\n\t\tif err := os.WriteFile(gitIgnorePath, []byte(\"*\\n\"), 0o644); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to create .gitignore file: %q %w\", gitIgnorePath, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n","sourceCodeStart":1,"sourceCodeEnd":23,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/backend/util.go#L1-L23","documentation":"createDotCrushDir creates the workspace data directory (mode 0700) and this error wraps os.MkdirAll failure. The quoted %q shows exactly which directory path could not be created, alongside the underlying OS error. It aborts workspace creation because subsequent data (DB, config) cannot live without the directory.","triggerScenarios":"Calling CreateWorkspace (indirectly via createDotCrushDir) when os.MkdirAll(dir, 0o700) fails — parent path doesn't exist and can't be created, permission denied on a parent, the path exists as a regular file, or the filesystem is read-only.","commonSituations":"Pointing the data dir at a read-only mount (containers, CI sandboxes); a file named .crush already exists where a directory is expected; running as a user without write access to the parent directory; HOME unset or mispointed.","solutions":["Read the quoted path and underlying OS error to identify permission vs existence issues.","If a regular file occupies the path, remove or rename it and retry.","Check write permission on the parent directory (ls -ld on each component).","Choose a different data directory on a writable filesystem."],"exampleFix":"// before\n// crash on read-only HOME\ncreateDotCrushDir(filepath.Join(os.Getenv(\"HOME\"), \".crush\"))\n// after\n// pick a writable location explicitly\ndir := os.Getenv(\"CRUSH_DATA_DIR\")\nif dir == \"\" {\n    dir = filepath.Join(os.TempDir(), \"crush-data\")\n}\nerr := createDotCrushDir(dir)","handlingStrategy":"validation","validationCode":"if fi, err := os.Stat(dir); err == nil {\n    if !fi.IsDir() {\n        return fmt.Errorf(\"%s exists and is not a directory\", dir)\n    }\n}\nparent := filepath.Dir(dir)\nif fi, err := os.Stat(parent); err != nil || !fi.IsDir() {\n    return fmt.Errorf(\"parent %s missing\", parent)\n}\nif err := unix.Access(parent, unix.W_OK); err != nil {\n    return fmt.Errorf(\"parent %s not writable: %w\", parent, err)\n}","typeGuard":"func IsMkdirErr(err error) (string, bool) {\n    var pe *fs.PathError\n    if errors.As(err, &pe) && errors.Is(pe.Err, fs.ErrExist) || errors.Is(err, fs.ErrPermission) {\n        return pe.Path, true\n    }\n    return \"\", false\n}","tryCatchPattern":"if err := createDotCrushDir(dir); err != nil {\n    var pe *fs.PathError\n    if errors.As(err, &pe) && errors.Is(pe.Err, fs.ErrPermission) {\n        // fall back to a writable data dir\n        return createDotCrushDir(filepath.Join(os.TempDir(), \"crush\"))\n    }\n    return err\n}","preventionTips":["Verify the target path is not an existing regular file before creating.","Run the process as a user with write access to the chosen data location.","Avoid read-only mounts (containers, CI) for data directories; use a volume or env override.","Set HOME/CRUSH data dir explicitly in sandboxed environments."],"tags":["filesystem","mkdir","permissions","go"],"backgroundTag":"mkdir-permission-denied","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}