kataras/iris · error
dest directory: %s: eval symlinks: %w
Error message
dest directory: %s: eval symlinks: %w
What it means
Returned by the multipart save/upload helpers when filepath.EvalSymlinks fails to resolve the canonical path of the destination directory (prefixDir). EvalSymlinks errors if any path component does not exist or is an unresolvable symlink, meaning the configured upload destination is broken or absent. The library fails closed rather than writing to an unverified location.
Source
Thrown at context/context.go:2429
if !isValidFilename {
// Reject the input as it is invalid or unsafe.
return prefixDir, name, false, nil
}
if ValidExtensionRegexp != nil && !ValidExtensionRegexp.MatchString(filename) {
// Reject the input as it is invalid or unsafe.
return prefixDir, name, false, nil
}
var destPath string
if prefixDir != "" {
// Join the sanitized input with the destination directory.
destPath = filepath.Join(prefixDir, filename)
// Get the canonical path of the destination directory.
canonicalDestDir, err := filepath.EvalSymlinks(prefixDir) // the prefix dir should exists.
if err != nil {
return prefixDir, name, false, fmt.Errorf("dest directory: %s: eval symlinks: %w", prefixDir, err)
}
// Check if the destination path is within the destination directory.
if !strings.HasPrefix(destPath, canonicalDestDir) {
// Reject the input as it is a path traversal attempt.
return prefixDir, name, false, nil
}
}
return destPath, filename, true, nil
}
// UploadFormFiles uploads any received file(s) from the client
// to the system physical location "destDirectory".
//
// The second optional argument "before" gives caller the chance to
// modify or cancel the *miltipart.FileHeader before saving to the disk,
// it can be used to change a file's name based on the current request,View on GitHub (pinned to 7bedaf55a0)
Solutions
- Create the destination directory with os.MkdirAll(prefixDir, 0o755) before calling the upload API.
- Verify the directory exists and all symlinks resolve in your deployment.
- Log the wrapped EvalSymlinks error from the message to identify the exact failing component.
- Avoid dangling symlinks in the upload root; use real directories in production.
Example fix
// before
dir := cfg.UploadDir
ctx.UploadFormFiles(dir)
// after
dir := cfg.UploadDir
if err := os.MkdirAll(dir, 0o755); err != nil {
return fmt.Errorf("prepare upload dir: %w", err)
}
ctx.UploadFormFiles(dir) Defensive patterns
Strategy: validation
Validate before calling
if _, err := os.Stat(uploadDir); err != nil {
return fmt.Errorf("upload dir unusable: %w", err)
}
if _, err := filepath.EvalSymlinks(uploadDir); err != nil {
return fmt.Errorf("upload dir symlink broken: %w", err)
} Type guard
func uploadDirReady(dir string) bool {
fi, err := os.Stat(dir)
return err == nil && fi.IsDir()
} Try / catch
path, name, ok, err := ctx.SaveFormFile(fh)
if err != nil {
if strings.Contains(err.Error(), "eval symlinks") {
return fmt.Errorf("upload destination invalid: %w", err)
}
return err
} Prevention
- Always os.MkdirAll the destination before saving uploads
- Avoid symlinked upload roots in production; use real directories
- Health-check the upload directory at startup, not at first upload
When it happens
Trigger: ctx.UploadFormFiles/SaveFormFile with a dest directory that does not exist, was deleted at runtime, contains a dangling symlink, or has a permission error on one of its components.
Common situations: Configured upload path points to a volume not mounted in the container; temp dir cleaned between restarts; symlinked upload roots removed by deploy scripts; permission-restricted directories.
Related errors
- ErrEmptyFormField
- ErrNotFound
- multipart related: body copy because of iris.Configuration.D
- multipart related: next part: %w
- multipart related: next part: read: %w
AI-assisted analysis of kataras/iris@7bedaf55a0 (2026-08-30).
Data as JSON: /api/errors/5d6aa8a7e5184397.
Report an issue: GitHub.