charmbracelet/crush · error
failed to create parent directories: %w
Error message
failed to create parent directories: %w
What it means
This error wraps an os.MkdirAll failure when MultiEdit creates a brand-new file and its parent directories don't yet exist. The tool needs the target directory present before writing; if mkdir fails (permissions, read-only fs, invalid path, path is a file), the whole new-file creation aborts with this wrapped error. It only fires on the new-file path of processMultiEditWithCreation.
Source
Thrown at internal/agent/tools/multiedit.go:165
func processMultiEditWithCreation(edit editContext, params MultiEditParams, call fantasy.ToolCall) (fantasy.ToolResponse, error) {
// First edit creates the file
firstEdit := params.Edits[0]
if firstEdit.OldString != "" {
return fantasy.NewTextErrorResponse("first edit must have empty old_string for file creation"), nil
}
// Check if file already exists
if _, err := os.Stat(params.FilePath); err == nil {
return fantasy.NewTextErrorResponse(fmt.Sprintf("file already exists: %s", params.FilePath)), nil
} else if !os.IsNotExist(err) {
return fantasy.ToolResponse{}, fmt.Errorf("failed to access file: %w", err)
}
// Create parent directories
dir := filepath.Dir(params.FilePath)
if err := os.MkdirAll(dir, 0o755); err != nil {
return fantasy.ToolResponse{}, fmt.Errorf("failed to create parent directories: %w", err)
}
currentContent, failedEdits, whitespaceCorrected := applyEditsToContent(firstEdit.NewString, params.Edits[1:], 1)
// Get session and message IDs
sessionID := GetSessionFromContext(edit.ctx)
if sessionID == "" {
return fantasy.ToolResponse{}, fmt.Errorf("session ID is required for creating a new file")
}
// Check permissions
_, additions, removals := diff.GenerateDiff("", currentContent, strings.TrimPrefix(params.FilePath, edit.workingDir))
editsApplied := len(params.Edits) - len(failedEdits)
var description string
if len(failedEdits) > 0 {
description = fmt.Sprintf("Create file %s with %d of %d edits (%d failed)", params.FilePath, editsApplied, len(params.Edits), len(failedEdits))
} else {View on GitHub (pinned to 7944b8e522)
Solutions
- Check that no path component of the target is an existing regular file; pick a different path or remove the blocking file
- Verify the process has write permission on the closest existing ancestor directory (ls -ld)
- If the filesystem is read-only, remount rw or run from a writable directory
- Fix the underlying OS error surfaced by %w in the message
Example fix
// before
os.WriteFile("src/missing/new.go", data, 0o644) // parent missing or blocked
// after
if err := os.MkdirAll(filepath.Dir("src/missing/new.go"), 0o755); err != nil { return err }
os.WriteFile("src/missing/new.go", data, 0o644) Defensive patterns
Strategy: validation
Validate before calling
if dir := filepath.Dir(p); dir != "." {
if st, err := os.Stat(dir); err == nil && !st.IsDir() {
return fmt.Errorf("%s exists and is not a directory", dir)
}
}
if err := os.MkdirAll(filepath.Dir(p), 0o755); err != nil { return err } Try / catch
var pathErr *os.PathError
if errors.As(err, &pathErr) {
switch errors.Unwrap(err) {
case syscall.EACCES: /* fix perms */
case syscall.ENOTDIR: /* fix path */
}
} Prevention
- Run the agent from a writable directory
- Never name a file component the same as an intended directory
- Check free space and mount flags (ro) before bulk edits
- Read the wrapped os.PathError to identify the failing component
When it happens
Trigger: Calling MultiEdit with a file_path whose directory does not exist or cannot be created: os.MkdirAll returns EACCES, ENOTDIR (a path component is a regular file), EROFS, or a name-too-long error.
Common situations: Running crush in a read-only container or project directory; the agent hallucinating a path where a file component exists as a directory (e.g. src/main.go already a file and target src/main.go/new.go); disk-full or SELinux/ACL denial on the working dir.
Related errors
- failed to write file: %w
- failed to create parent directories: %w
- failed to create output file: %w
- failed to access file: %w
- failed to create parent directories: %w
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/6606fe6a02e62e4b.
Report an issue: GitHub.