{"record":{"id":"c818e4771bd79f33","repo":"charmbracelet/crush","slug":"failed-to-create-data-directory-w","errorCode":null,"errorMessage":"failed to create data directory: %w","messagePattern":"failed to create data directory: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/backend.go","lineNumber":423,"sourceCode":"\t\tshutdownNow := b.scheduleShutdownIfIdleLocked()\n\t\tb.mu.Unlock()\n\t\tif shutdownNow {\n\t\t\tslog.Info(\"No workspaces remain after create settled, shutting down server...\")\n\t\t\tb.shutdownFn()\n\t\t}\n\t}()\n\n\tid := uuid.New().String()\n\tcfg, err := config.Init(args.Path, args.DataDir, args.Debug)\n\tif err != nil {\n\t\treturn nil, proto.Workspace{}, fmt.Errorf(\"failed to initialize config: %w\", err)\n\t}\n\n\tcfg.Overrides().SkipPermissionRequests = args.YOLO\n\tcfg.Overrides().EnabledChannels = args.Channels\n\n\tif err := createDotCrushDir(cfg.Config().Options.DataDirectory); err != nil {\n\t\treturn nil, proto.Workspace{}, fmt.Errorf(\"failed to create data directory: %w\", err)\n\t}\n\n\tconn, err := db.Connect(b.ctx, cfg.Config().Options.DataDirectory, db.WithDataDirLock(true))\n\tif err != nil {\n\t\treturn nil, proto.Workspace{}, fmt.Errorf(\"failed to connect to database: %w\", err)\n\t}\n\n\t// Discover skills once per workspace, before app.New. The backend\n\t// hosts multiple workspaces concurrently, so the manager is\n\t// constructed WITHOUT WithGlobalMirror to prevent last-writer-wins\n\t// cross-talk between workspaces.\n\tdiscoveryCfg := skillsDiscoveryConfig(cfg)\n\tallSkills, activeSkills, skillStates := skills.DiscoverFromConfig(discoveryCfg)\n\tskillsMgr := skills.NewManager(\n\t\tallSkills, activeSkills, skillStates,\n\t\tskills.WithResolvedPaths(discoveryCfg.ResolvePaths()),\n\t\tskills.WithWorkingDir(discoveryCfg.WorkingDir),\n\t)","sourceCodeStart":405,"sourceCodeEnd":441,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/backend/backend.go#L405-L441","documentation":"CreateWorkspace calls createDotCrushDir on the configured data directory to ensure the .crush storage location exists. Failure to create it (permissions, read-only FS, path is a file) is wrapped with this message.","triggerScenarios":"cfg.Config().Options.DataDirectory cannot be MkdirAll'd — parent dir not writable, path exists as a regular file, disk full, or read-only mount.","commonSituations":"Running in a sandbox/container with read-only home; DATA_DIR pointing at a file; running as a different user than the directory owner.","solutions":["Check/fix permissions on the data directory's parent and recreate with mkdir","Point the data directory override at a writable location","Remove any regular file occupying the data-directory path"],"exampleFix":"// before\ncrush run  # ~/.crush owned by root\n// after\nsudo chown -R $USER ~/.crush\n# or set a writable data dir\ncrush run --data-dir /tmp/crush-data","handlingStrategy":"validation","validationCode":"dataDir := cfg.Config().Options.DataDirectory\nif fi, err := os.Stat(dataDir); err == nil && !fi.IsDir() {\n    return fmt.Errorf(\"data dir %s exists and is not a directory\", dataDir)\n}\nif err := os.MkdirAll(dataDir, 0o755); err != nil {\n    return fmt.Errorf(\"cannot create data dir: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"failed to create data directory\") {\n    return fmt.Errorf(\"check permissions/writability of data dir: %w\", err)\n}","preventionTips":["Run crush as a user with write access to the data directory","Avoid read-only or NFS mounts for the data directory","Override the data dir explicitly in sandboxes/containers"],"tags":["filesystem","permissions","data-directory"],"backgroundTag":"mkdir-permission-denied","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}