labstack/echo · error

failed to parse form value, key

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.

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.

Understand the failure class

Related errors


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

Appendix: 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)