gofiber/fiber · error
failed to create directory
Error message
failed to create directory: %w
What it means
Response.Save attempts os.MkdirAll(dir, 0o750) when the target directory does not exist. This wraps a failure of that call: a parent component is a file (ENOTDIR), permission denied (EACCES), or read-only filesystem.
Solutions
- Use a save directory known to be writable by the process (e.g. os.TempDir()).
- Resolve the full path and ensure no ancestor is a regular file before calling Save.
- Mount a writable volume at the save location in containerized deployments.
Example fix
// before
if err := resp.Save("/var/lock/downloads/out.bin"); err != nil { ... }
// after
dir := filepath.Join(os.TempDir(), "downloads")
_ = os.MkdirAll(dir, 0o750)
if err := resp.Save(filepath.Join(dir, "out.bin")); err != nil { ... } Defensive patterns
Strategy: validation
Validate before calling
if err := os.MkdirAll(dir, 0o750); err != nil {
return fmt.Errorf("cannot use save dir %q: %w", dir, err)
} Prevention
- Write into a directory the process owns (e.g. under os.TempDir()).
- Ensure no ancestor of the save path is a regular file.
- Mount a writable volume in containers at the save path.
When it happens
Trigger: The save path's parent doesn't exist and cannot be created; a parent in the chain is a regular file; the process cannot write to the location; mount is read-only.
Common situations: User-supplied download paths; containers with read-only volumes; chroot/jail missing a writable directory; path collision where an ancestor is a file.
Related errors
- failed to check directory
- failed to create file
- failed to write response body to file
- failed to write response body to writer
- open file error
AI-assisted analysis of gofiber/fiber@a105acad6c (2026-08-11).
Data as JSON: /api/errors/6c4cb38364f76b0b.
Report an issue: GitHub.
Appendix: source
Thrown at client/response.go:199
// Save writes the response body to a file or io.Writer.
// If a string path is provided, it creates directories if needed, then writes to a file.
// If an io.Writer is provided, it writes directly to it.
// When streaming is enabled, the body is read directly from the stream.
func (r *Response) Save(v any) error {
switch p := v.(type) {
case string:
file := filepath.Clean(p)
dir := filepath.Dir(file)
// Create directory if it doesn't exist
if _, err := os.Stat(dir); err != nil {
if !errors.Is(err, fs.ErrNotExist) {
return fmt.Errorf("failed to check directory: %w", err)
}
if err = os.MkdirAll(dir, 0o750); err != nil {
return fmt.Errorf("failed to create directory: %w", err)
}
}
// Create and write to file
outFile, err := os.Create(file)
if err != nil {
return fmt.Errorf("failed to create file: %w", err)
}
defer func() { _ = outFile.Close() }() //nolint:errcheck // not needed
// Use BodyStream() which handles both streaming and non-streaming cases
if _, err = io.Copy(outFile, r.BodyStream()); err != nil {
return fmt.Errorf("failed to write response body to file: %w", err)
}
return nil
case io.Writer:View on GitHub (pinned to a105acad6c)