labstack/echo · error

failed to parse form value, key: %s, err: %w

Error message

failed to parse form value, key: %s, err: %w

What it means

Returned by echo.FormValue[T] (binder_generic.go:213-218) when the underlying c.FormValues() call failed, wrapped with the offending key. The generic parse never started — the request body could not be parsed as form data. Distinguish from ErrNonExistentKey which is returned only when parsing succeeds but the key is absent.

Source

Thrown at binder_generic.go:217

	return result, nil
}

// FormValue extracts and parses a single form value from the request by key.
// It returns the typed value and an error if binding fails. Returns ErrNonExistentKey if parameter not found.
//
// Empty String Handling:
//
//	If the form field exists but has an empty value, the zero value of type T is returned
//	with no error. For example, an empty form field returns (0, nil) for int types.
//	This differs from standard library behavior where parsing empty strings returns errors.
//	To treat empty values as errors, validate the result separately or check the raw value.
//
// See ParseValue for supported types and options
func FormValue[T any](c *Context, key string, opts ...any) (T, error) {
	formValues, err := c.FormValues()
	if err != nil {
		var zero T
		return zero, fmt.Errorf("failed to parse form value, key: %s, err: %w", key, err)
	}
	values, ok := formValues[key]
	if !ok {
		var zero T
		return zero, ErrNonExistentKey
	}
	if len(values) == 0 {
		var zero T
		return zero, nil
	}
	value := values[0]
	v, err := ParseValue[T](value, opts...)
	if err != nil {
		return v, NewBindingError(key, []string{value}, "form value", err)
	}
	return v, nil
}

View on GitHub (pinned to 05489dc173)

Solutions

  1. Ensure the client sends application/x-www-form-urlencoded or multipart/form-data
  2. Raise MaxRequestSize / multipart memory limits if body parsing hit a cap
  3. For JSON clients use c.Bind(&struct{}) instead of FormValue

Example fix

// before
page, err := echo.FormValue[int](c, "page")
// after — validate content type, and switch to JSON binding for JSON clients:
if !isFormContent(c) {
    return c.JSON(http.StatusUnsupportedMediaType, map[string]string{"error": "form content-type required"})
}
page, err := echo.FormValue[int](c, "page")
Defensive patterns

Strategy: try-catch

Validate before calling

ct := c.Request().Header.Get("Content-Type")
if !strings.HasPrefix(ct, "application/x-www-form-urlencoded") && !strings.HasPrefix(ct, "multipart/form-data") {
    return c.JSON(http.StatusUnsupportedMediaType, map[string]string{"error": "form content-type required"})
}

Try / catch

v, err := echo.FormValue[int](c, "page")
if err != nil {
    return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid form: " + err.Error()})
}

Prevention

When it happens

Trigger: Calling FormValue[int](c, "page") on a request whose multipart body is malformed, whose Content-Type is not form/multipart, or whose multipart.Parse returned an error (bad boundary, body too large).

Common situations: Wrong Content-Type (client sending JSON to a form handler), exceeded MaxRequestSize / multipart memory, corrupted multipart boundary, truncated body.

Related errors


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