{"record":{"id":"1e3097d6502482cd","repo":"charmbracelet/crush","slug":"error-creating-directory-w","errorCode":null,"errorMessage":"error creating directory: %w","messagePattern":"error creating directory: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/agent/tools/write.go","lineNumber":91,"sourceCode":"\n\t\t\t\tmodTime := fileInfo.ModTime().Truncate(time.Second)\n\t\t\t\tlastRead := filetracker.LastReadTime(ctx, sessionID, filePath)\n\t\t\t\tif modTime.After(lastRead) {\n\t\t\t\t\treturn fantasy.NewTextErrorResponse(fmt.Sprintf(\"File %s has been modified since it was last read.\\nLast modification: %s\\nLast read: %s\\n\\nPlease read the file again before modifying it.\",\n\t\t\t\t\t\tfilePath, modTime.Format(time.RFC3339), lastRead.Format(time.RFC3339))), nil\n\t\t\t\t}\n\n\t\t\t\toldContent, readErr := os.ReadFile(filePath)\n\t\t\t\tif readErr == nil && string(oldContent) == params.Content {\n\t\t\t\t\treturn fantasy.NewTextErrorResponse(fmt.Sprintf(\"File %s already contains the exact content. No changes made.\", filePath)), nil\n\t\t\t\t}\n\t\t\t} else if !os.IsNotExist(err) {\n\t\t\t\treturn fantasy.ToolResponse{}, fmt.Errorf(\"error checking file: %w\", err)\n\t\t\t}\n\n\t\t\tdir := filepath.Dir(filePath)\n\t\t\tif err = os.MkdirAll(dir, 0o755); err != nil {\n\t\t\t\treturn fantasy.ToolResponse{}, fmt.Errorf(\"error creating directory: %w\", err)\n\t\t\t}\n\n\t\t\toldContent := \"\"\n\t\t\tif fileInfo != nil && !fileInfo.IsDir() {\n\t\t\t\toldBytes, readErr := os.ReadFile(filePath)\n\t\t\t\tif readErr == nil {\n\t\t\t\t\toldContent = string(oldBytes)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdiff, additions, removals := diff.GenerateDiff(\n\t\t\t\toldContent,\n\t\t\t\tparams.Content,\n\t\t\t\tstrings.TrimPrefix(filePath, workingDir),\n\t\t\t)\n\n\t\t\tp, err := permissions.Request(\n\t\t\t\tctx,","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/agent/tools/write.go#L73-L109","documentation":"The write tool creates missing parent directories with os.MkdirAll(dir, 0o755) before writing the file. If that fails, the tool wraps the OS error and aborts. MkdirAll fails when it lacks permission on an ancestor, an ancestor exists as a non-directory, or the filesystem rejects the create.","triggerScenarios":"Target file_path has a directory component that does not exist and cannot be created — parent owned by another user/read-only mount, or an ancestor path is a regular file (ENOTDIR), or the filesystem is full (ENOSPC).","commonSituations":"Agent running as a non-root user writing under /etc or another root-owned path; read-only container filesystems; path like src/main.go/newdir/file.go where main.go is a file; disk quota exceeded.","solutions":["Ensure the process user can create the directory: check ownership and write permission on the nearest existing ancestor.","Fix the path so no intermediate component is a regular file.","Check disk space/quota (df -h, ENOSPC).","Write within the project working directory instead of system paths."],"exampleFix":"// before\n{\"file_path\": \"/etc/myapp/config.json\", \"content\": \"{}\"}\n\n// after\n{\"file_path\": \"config/config.json\", \"content\": \"{}\"}","handlingStrategy":"validation","validationCode":"dir := filepath.Dir(targetPath)\nif err := os.MkdirAll(dir, 0o755); err != nil {\n    return fmt.Errorf(\"cannot create %s: %w\", dir, err)\n}","typeGuard":null,"tryCatchPattern":"if err != nil {\n    if errors.Is(err, fs.ErrPermission) {\n        return fmt.Errorf(\"mkdir denied: run the agent as a user that owns the project dir\")\n    }\n    if errors.Is(err, syscall.ENOTDIR) {\n        return fmt.Errorf(\"a path component is a file, not a directory\")\n    }\n    return err\n}","preventionTips":["Use relative paths within the project root; avoid system directories.","Ensure no file in the repo shares a name with an intended directory component.","Monitor disk space on CI runners."],"tags":["go","filesystem","mkdir","permissions"],"backgroundTag":"mkdir-permission-denied","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}