{"record":{"id":"d5170763c72d0aea","repo":"charmbracelet/crush","slug":"failed-to-create-data-directory-q-w-d51707","errorCode":null,"errorMessage":"failed to create data directory: %q %w","messagePattern":"failed to create data directory: %q %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"internal/cmd/root.go","lineNumber":292,"sourceCode":"\tdataDir, _ := cmd.Flags().GetString(\"data-dir\")\n\tctx := cmd.Context()\n\n\tcwd, err := ResolveCwd(cmd)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tstore, err := config.Init(cwd, dataDir, debug)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tcfg := store.Config()\n\tstore.Overrides().SkipPermissionRequests = yolo\n\tstore.Overrides().EnabledChannels = channels\n\n\tif err := os.MkdirAll(cfg.Options.DataDirectory, 0o700); err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"failed to create data directory: %q %w\", cfg.Options.DataDirectory, err)\n\t}\n\n\tgitIgnorePath := filepath.Join(cfg.Options.DataDirectory, \".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 nil, nil, fmt.Errorf(\"failed to create .gitignore file: %q %w\", gitIgnorePath, err)\n\t\t}\n\t}\n\n\tif err := projects.Register(cwd, cfg.Options.DataDirectory); err != nil {\n\t\tslog.Warn(\"Failed to register project\", \"error\", err)\n\t}\n\n\tconn, err := db.Connect(ctx, cfg.Options.DataDirectory)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n","sourceCodeStart":274,"sourceCodeEnd":310,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/cmd/root.go#L274-L310","documentation":"setupLocalWorkspace in internal/cmd/root.go creates the data directory (crush's state dir) with os.MkdirAll 0o700. If the OS refuses (bad path, permission denied, parent not writable, path is a file), it returns 'failed to create data directory: %q %w'. Startup aborts since crush cannot persist sessions/state.","triggerScenarios":"DataDirectory configured to a path whose parent is not writable; a regular file already exists at the path; read-only filesystem; restricted sandbox/containers blocking mkdir; invalid characters or empty path.","commonSituations":"Running crush in a read-only container or CI sandbox; HOME unset so path resolves oddly; overriding data directory in config to a root-owned location; disk full or quota exceeded.","solutions":["Check the printed path: ensure no file exists there (rm/mv it if so) and its parent is writable","Fix permissions: mkdir -p and chown/chmod the parent directory","Set a writable data directory in crush config (options/data_directory) e.g. under $HOME","Run outside read-only sandboxes or mount a writable volume for the data dir"],"exampleFix":"// before\ncfg.Options.DataDirectory = \"/var/lib/crush\" // root-owned, not writable\n// after\ncfg.Options.DataDirectory = filepath.Join(os.Getenv(\"HOME\"), \".local\", \"share\", \"crush\")","handlingStrategy":"validation","validationCode":"dir := cfg.Options.DataDirectory\nif fi, err := os.Stat(dir); err == nil && !fi.IsDir() {\n    return fmt.Errorf(\"data directory path %s is a file\", dir)\n}\nif err := os.MkdirAll(dir, 0o700); err != nil {\n    return fmt.Errorf(\"cannot create %s: %w\", dir, err)\n}","typeGuard":null,"tryCatchPattern":"if err := os.MkdirAll(dataDir, 0o700); err != nil {\n    var pe *fs.PathError\n    if errors.As(err, &pe) && errors.Is(pe.Err, syscall.EACCES) {\n        // fix permissions or pick another dir\n    }\n    return err\n}","preventionTips":["Point data_directory at a user-writable path (e.g. $XDG_DATA_HOME/crush)","Never place a file at the data directory path","Avoid read-only containers without a writable volume for state"],"tags":["filesystem","permissions","startup","data-directory"],"backgroundTag":"mkdir-permission-denied","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}