labstack/echo · error

%s: %w

Error message

%s: %w

What it means

A wrapping error (fmt.Errorf with %w) from bindData at line 322, produced when unmarshalInputsToField fails. This path handles fields implementing the bindMultipleUnmarshaler interface (UnmarshalParams([]string) error) and their UnmarshalParams call returned an error. The field name is prefixed (e.g. "tags: <inner error>") so the caller knows which field failed, and the inner error is wrapped for errors.Is/As.

Source

Thrown at bind.go:322

				if strings.EqualFold(k, inputFieldName) {
					inputValue = v
					exists = true
					break
				}
			}
		}

		if !exists {
			continue
		}

		// NOTE: algorithm here is not particularly sophisticated. It probably does not work with absurd types like `**[]*int`
		// but it is smart enough to handle niche cases like `*int`,`*[]string`,`[]*int` .

		// try unmarshalling first, in case we're dealing with an alias to an array type
		if ok, err := unmarshalInputsToField(fm.fieldKind, inputValue, structField); ok {
			if err != nil {
				return fmt.Errorf("%s: %w", inputFieldName, err)
			}
			continue
		}

		if ok, err := unmarshalInputToField(fm.fieldKind, inputValue[0], structField, fm.formatTag); ok {
			if err != nil {
				return fmt.Errorf("%s: %w", inputFieldName, err)
			}
			continue
		}

		// we could be dealing with pointer to slice `*[]string` so dereference it. There are weird OpenAPI generators
		// that could create struct fields like that.
		if structFieldKind == reflect.Pointer {
			structFieldKind = structField.Elem().Kind()
			structField = structField.Elem()
		}

View on GitHub (pinned to 05489dc173)

Solutions

  1. Inspect the wrapped error via errors.Unwrap/errors.Is to determine the exact parse failure
  2. Fix the client input to match the expected format for that field
  3. Make the UnmarshalParams implementation more lenient or return a clearer error message

Example fix

// custom type returning error from UnmarshalParams
type Tags []string
func (t *Tags) UnmarshalParams(vals []string) error {
    if len(vals) > 5 { return errors.New("max 5 tags") }
    *t = vals
    return nil
}
// error returned: "tags: max 5 tags"
// fix: send <= 5 tags, or raise the limit in UnmarshalParams
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate multi-value params before they reach UnmarshalParams
func validateSliceValues(vals []string, max int) error {
    if len(vals) > max {
        return fmt.Errorf("too many values: %d > %d", len(vals), max)
    }
    return nil
}

Try / catch

if err := c.Bind(&req); err != nil {
    var he *echo.HTTPError
    if errors.As(err, &he) || strings.Contains(err.Error(), ":") {
        // field-level bind error; extract field name from prefix
        fieldName := strings.SplitN(err.Error(), ":", 2)[0]
        return echo.NewHTTPError(http.StatusBadRequest, "invalid value for "+fieldName)
    }
    return err
}

Prevention

When it happens

Trigger: Binding multiple query/form values (e.g. ?tag=a&tag=b) into a field whose type implements UnmarshalParams([]string) error, and the implementation returns an error such as invalid format, too many values, or domain validation failure.

Common situations: Custom slice or collection types with an UnmarshalParams implementation enforcing constraints (max items, allowed values). Custom enum or time types parsing multiple inputs.

Related errors


AI-assisted analysis of labstack/echo@05489dc173 (2026-08-04). Data as JSON: /data/errors/ee2535efa9ce40d0.json. Report an issue: GitHub.