Browse code

fix: return 400 instead of 500 for invalid request parameters

Wrap plain errors with errdefs.InvalidParameter so the API returns
HTTP 400 instead of 500 for user input errors:

- image export: invalid reference format
- container stop/list: invalid integer for t/limit params
- plugin privileges: invalid reference format
- plugin enable: invalid integer for timeout param
- service/task logs: missing stdout/stderr stream selection

Fixes #48173

Signed-off-by: Ogulcan Aydogan <ogulcanaydogan@hotmail.com>

Ogulcan Aydogan authored on 2026/03/30 05:20:09
Showing 3 changed files
... ...
@@ -24,6 +24,7 @@ import (
24 24
 	"github.com/moby/moby/v2/daemon/internal/ioutils"
25 25
 	"github.com/moby/moby/v2/daemon/internal/layer"
26 26
 	"github.com/moby/moby/v2/daemon/internal/system"
27
+	"github.com/moby/moby/v2/errdefs"
27 28
 	"github.com/moby/sys/sequential"
28 29
 	"github.com/opencontainers/go-digest"
29 30
 	"github.com/opencontainers/image-spec/specs-go"
... ...
@@ -104,7 +105,7 @@ func (l *tarexporter) parseNames(ctx context.Context, names []string) (desc map[
104 104
 
105 105
 		ref, err := reference.ParseAnyReference(name)
106 106
 		if err != nil {
107
-			return nil, err
107
+			return nil, errdefs.InvalidParameter(err)
108 108
 		}
109 109
 		namedRef, ok := ref.(reference.Named)
110 110
 		if !ok {
... ...
@@ -112,7 +112,7 @@ func (c *containerRouter) getContainersJSON(ctx context.Context, w http.Response
112 112
 	if tmpLimit := r.Form.Get("limit"); tmpLimit != "" {
113 113
 		val, err := strconv.Atoi(tmpLimit)
114 114
 		if err != nil {
115
-			return err
115
+			return errdefs.InvalidParameter(err)
116 116
 		}
117 117
 		limit = val
118 118
 	}
... ...
@@ -293,7 +293,7 @@ func (c *containerRouter) postContainersStop(ctx context.Context, w http.Respons
293 293
 	if tmpSeconds := r.Form.Get("t"); tmpSeconds != "" {
294 294
 		valSeconds, err := strconv.Atoi(tmpSeconds)
295 295
 		if err != nil {
296
-			return err
296
+			return errdefs.InvalidParameter(err)
297 297
 		}
298 298
 		options.Timeout = &valSeconds
299 299
 	}
... ...
@@ -14,6 +14,7 @@ import (
14 14
 	"github.com/moby/moby/v2/daemon/internal/streamformatter"
15 15
 	"github.com/moby/moby/v2/daemon/server/backend"
16 16
 	"github.com/moby/moby/v2/daemon/server/httputils"
17
+	"github.com/moby/moby/v2/errdefs"
17 18
 	"github.com/moby/moby/v2/pkg/ioutils"
18 19
 	"github.com/pkg/errors"
19 20
 )
... ...
@@ -40,7 +41,7 @@ func parseRemoteRef(remote string) (reference.Named, string, error) {
40 40
 	// Parse remote reference, supporting remotes with name and tag
41 41
 	remoteRef, err := reference.ParseNormalizedNamed(remote)
42 42
 	if err != nil {
43
-		return nil, "", err
43
+		return nil, "", errdefs.InvalidParameter(err)
44 44
 	}
45 45
 
46 46
 	type canonicalWithTag interface {
... ...
@@ -205,7 +206,7 @@ func (pr *pluginRouter) enablePlugin(ctx context.Context, w http.ResponseWriter,
205 205
 
206 206
 	timeout, err := strconv.Atoi(r.Form.Get("timeout"))
207 207
 	if err != nil {
208
-		return err
208
+		return errdefs.InvalidParameter(err)
209 209
 	}
210 210
 
211 211
 	name := vars["name"]