docker/cli · error
failed to save image
Error message
failed to save image: %w
What it means
Returned by `docker image save` / `docker save` when the atomic output file cannot be created via `atomicwriter.New(opts.output, 0o600)` (save.go:77-79). atomicwriter writes to a temp file then renames, so this fails when the path is invalid, the parent directory is missing, or the process lacks write permission. The %w wraps the underlying OS error (e.g. EACCES, ENOENT, EISDIR).
Solutions
- Verify the parent directory of -o exists and is writable: `mkdir -p $(dirname OUT) && touch OUT`.
- Ensure -o points to a file path, not an existing directory.
- Drop -o and pipe to a writable location: `docker save img > out.tar`.
- Check disk space and that the filesystem is mounted read-write.
Example fix
# before docker save -o /tmp/missing-dir/img.tar myimage # after mkdir -p /tmp/missing-dir && docker save -o /tmp/missing-dir/img.tar myimage
Defensive patterns
Strategy: validation
Validate before calling
// validate the -o output path before calling ImageSave
info, err := os.Stat(filepath.Dir(outputPath))
if err != nil || !info.IsDir() {
return fmt.Errorf("output directory for %q is not accessible: %w", outputPath, err)
}
if f, err := os.Create(outputPath); err != nil {
return fmt.Errorf("output path %q not writable: %w", outputPath, err)
} else {
f.Close()
os.Remove(outputPath)
} Try / catch
if err := runSave(ctx, cli, opts); err != nil {
if strings.Contains(err.Error(), "failed to save image") {
// surface an actionable hint about the -o path
log.Fatalf("save failed — check that -o path is a writable file in an existing directory: %v", err)
}
log.Fatal(err)
} Prevention
- Always mkdir -p the parent of -o before running docker save.
- Never point -o at an existing directory.
- In CI, mount the output volume read-write and verify with a touch probe.
When it happens
Trigger: Running `docker save -o /nonexistent/dir/img.tar img` (parent dir missing), `-o /some/dir` where the path is an existing directory, or `-o /root/file.tar` as a non-root user. Also triggered on read-only filesystems.
Common situations: Typos in the -o path, pointing -o at a directory instead of a file, running in a container/CI where the output mount is read-only, or a path with no permission.
Related errors
- invalid platform
- error closing temp file
- source can not be empty
- destination can not be empty
- copying between containers is not supported
AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07).
Data as JSON: /api/errors/d50b20b8f7ec7b86.
Report an issue: GitHub.
Appendix: source
Thrown at cli/command/image/save.go:79
if err != nil {
return fmt.Errorf("invalid platform: %w", err)
}
platformList = append(platformList, pp)
}
if len(platformList) > 0 {
options = append(options, client.ImageSaveWithPlatforms(platformList...))
}
var output io.Writer
if opts.output == "" {
if dockerCLI.Out().IsTerminal() {
return errors.New("cowardly refusing to save to a terminal. Use the -o flag or redirect")
}
output = dockerCLI.Out()
} else {
writer, err := atomicwriter.New(opts.output, 0o600)
if err != nil {
return fmt.Errorf("failed to save image: %w", err)
}
defer writer.Close()
output = writer
}
responseBody, err := dockerCLI.Client().ImageSave(ctx, opts.images, options...)
if err != nil {
return err
}
defer responseBody.Close()
_, err = io.Copy(output, responseBody)
return err
}
View on GitHub (pinned to 4f84911bfe)