From ff97459f01820987cab26d6c07e912396f2a856f Mon Sep 17 00:00:00 2001 From: Dean Chen <862469039@qq.com> Date: Tue, 11 Aug 2026 21:31:57 +0500 Subject: [PATCH] cli: print command errors before next-step hooks Error-hooks were writing "What's next" to stderr before main printed the failure, so the hint appeared above the actual error. Print the error first, then run hooks, and return a status-code-only error so main does not print it twice. Fixes #6973 Signed-off-by: Dean Chen <862469039@qq.com> --- cmd/docker/docker.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/cmd/docker/docker.go b/cmd/docker/docker.go index 0efcc70118fe..77f432cd1a9f 100644 --- a/cmd/docker/docker.go +++ b/cmd/docker/docker.go @@ -519,8 +519,18 @@ func runDocker(ctx context.Context, dockerCli *command.DockerCli) error { if err != nil || pluginmanager.IsPluginCommand(ccmd) { err := tryPluginRun(ctx, dockerCli, cmd, args[0], envs) if ccmd != nil && dockerCli.Out().IsTerminal() && dockerCli.HooksEnabled() && !errdefs.IsNotFound(err) { + // Print failure before next-step hints so they appear after the error. + if err != nil { + if msg := err.Error(); msg != "" { + _, _ = fmt.Fprintln(dockerCli.Err(), err) + } + } errMessage := cmdErrorMessage(err) pluginmanager.RunPluginHooks(ctx, dockerCli, cmd, ccmd, args, errMessage) + if err != nil { + // Already printed; keep exit code without a second print in main. + return cli.StatusError{StatusCode: getExitCode(err)} + } } if err == nil { return nil @@ -546,7 +556,18 @@ 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() { + // Print the command error before next-step hints. main() would + // otherwise print the error after hooks return (issue #6973). + if err != nil { + if msg := err.Error(); msg != "" { + _, _ = fmt.Fprintln(dockerCli.Err(), err) + } + } pluginmanager.RunCLICommandHooks(ctx, dockerCli, cmd, subCommand, cmdErrorMessage(err)) + if err != nil { + // Already printed; keep exit code without a second print in main. + return cli.StatusError{StatusCode: getExitCode(err)} + } } return err