From 14645ee3cf8a13c69b7003ead741550e74d840b8 Mon Sep 17 00:00:00 2001 From: adisivaprasad Date: Fri, 21 Aug 2026 12:04:43 -0700 Subject: [PATCH] cmd/docker: print command error before running plugin hooks When a CLI command fails and an error-hook (or hook) produces a "What's next" hint, the hint was printed before the command's error message. The command's error is only printed by main() after runDocker() returns, but plugin hooks run inside runDocker() right after cmd.ExecuteContext(). Print the pending command error to stderr before invoking the hooks, and replace the returned error with a silent cli.StatusError that only carries the exit code, so that main() does not print it a second time. Canceled and signal-terminated errors (which print nothing) are left untouched, and exit codes are unchanged. Signed-off-by: adisivaprasad --- cmd/docker/docker.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/cmd/docker/docker.go b/cmd/docker/docker.go index 0efcc70118fe..b364a68ca2c0 100644 --- a/cmd/docker/docker.go +++ b/cmd/docker/docker.go @@ -546,7 +546,20 @@ func runDocker(ctx context.Context, dockerCli *command.DockerCli) error { // If the command is being executed in an interactive terminal // and hook are enabled, run the plugin hooks. if subCommand != nil && dockerCli.Out().IsTerminal() && dockerCli.HooksEnabled() { - pluginmanager.RunCLICommandHooks(ctx, dockerCli, cmd, subCommand, cmdErrorMessage(err)) + errMessage := cmdErrorMessage(err) + + // If the command produced an error that has yet to be printed, + // print it before running hooks, so that hook output (such as + // "What's next" hints) is shown after the error message instead + // of before it. The error is replaced with a silent error that + // only carries the exit-code, so that main does not print the + // error a second time. + if err != nil && !errdefs.IsCanceled(err) && err.Error() != "" { + _, _ = fmt.Fprintln(dockerCli.Err(), err) + err = cli.StatusError{StatusCode: getExitCode(err)} + } + + pluginmanager.RunCLICommandHooks(ctx, dockerCli, cmd, subCommand, errMessage) } return err