docker/cli · error

server did not provide an image ID. Cannot write

Error message

server did not provide an image ID. Cannot write %s

What it means

Returned by runBuild (build.go:390) when --iidfile was requested but after a successful build the resolved imageID is empty. The CLI resolves the ID either from the daemon's aux JSON messages or, in quiet mode, from the build output buffer. An empty ID means the server stream completed without ever providing an image identifier, so there is nothing to write to the iidfile.

Solutions

  1. Re-run without --iidfile and inspect the full output to see if an ID is emitted at all.
  2. Ensure CLI and daemon versions are compatible: 'docker version' and align client/server.
  3. If using buildkit/buildx, prefer 'docker buildx build --iidfile <path>' which handles ID extraction for that backend.
  4. Check stderr for the 'Failed to parse aux message' line (build.go:359) which indicates an aux-schema mismatch.

Example fix

# before (classic builder + iidfile, daemon emits no ID)
DOCKER_BUILDKIT=1 docker build --iidfile id.txt .
# after (use buildx for buildkit builds)
docker buildx build --iidfile id.txt --load .
Defensive patterns

Strategy: validation

Validate before calling

// After a build, parse the iidfile to confirm an ID was written; if using buildkit,
// prefer buildx which reliably emits an ID.
func buildAndReadID(target string) (string, error) {
	cmd := exec.Command("docker", "buildx", "build", "--iidfile", target, "--load", ".")
	if err := cmd.Run(); err != nil { return "", err }
	return os.ReadFile(target)
}

Try / catch

if err := buildCmd.Execute(); err != nil {
	if strings.Contains(err.Error(), "server did not provide an image ID") {
		// daemon/backend mismatch; retry without --iidfile or switch to buildx
	}
}

Prevention

When it happens

Trigger: The daemon/build backend finished the build stream without emitting an 'aux' message containing Result.ID, and quiet mode produced no ID either. Seen with remote builders (buildkit/buildx backends) that stream differently, with daemons that emit a non-standard aux shape the CLI cannot parse (the parse error is only logged to stderr at build.go:359), or when the build actually failed server-side but closed the stream cleanly.

Common situations: Mixing an older CLI with a newer daemon (or vice versa) where the aux message schema changed; using DOCKER_BUILDKIT=1 with a buildkit version that emits IDs differently; a proxy/middlebox altering the stream; the build produced no final image (e.g., multi-stage with no default target).

Related errors


AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07). Data as JSON: /api/errors/f24f147b920d6e72. Report an issue: GitHub.

Appendix: source

Thrown at cli/command/image/build.go:390

			}
			if options.quiet {
				_, _ = fmt.Fprintf(dockerCli.Err(), "%s%s", progBuff, buildBuff)
			}
			return cli.StatusError{Status: jerr.Message, StatusCode: jerr.Code}
		}
		return err
	}

	// Everything worked so if -q was provided the output from the daemon
	// should be just the image ID and we'll print that to stdout.
	if options.quiet {
		imageID = fmt.Sprintf("%s", buildBuff)
		_, _ = fmt.Fprint(dockerCli.Out(), imageID)
	}

	if options.imageIDFile != "" {
		if imageID == "" {
			return fmt.Errorf("server did not provide an image ID. Cannot write %s", options.imageIDFile)
		}
		if err := os.WriteFile(options.imageIDFile, []byte(imageID), 0o666); err != nil {
			return err
		}
	}

	return nil
}

// validateTag checks if the given image name can be resolved.
func validateTag(rawRepo string) (string, error) {
	_, err := reference.ParseNormalizedNamed(rawRepo)
	if err != nil {
		return "", err
	}

	return rawRepo, nil
}

View on GitHub (pinned to 4f84911bfe)