go-chi/chi · error · ErrResponse

missing required Article fields.

Error message

missing required Article fields.

What it means

Returned by (*ArticleRequest).Bind after render.Bind decodes the incoming JSON body. The embedded *Article pointer is only populated if the JSON contains fields that map onto Article; an empty body or a body lacking every Article field leaves a.Article == nil, so Bind rejects the request to avoid a later nil-pointer dereference in handlers like CreateArticle. It surfaces to the client as a 400 'Invalid request.' ErrResponse whose ErrorText is this message. It is an application-level validation error, not something thrown by chi itself.

Source

Thrown at _examples/rest/main.go:331

// so you can manage the specific inputs and outputs for clients, and also gives
// you the opportunity to transform data on input or output, for example
// on request, we'd like to protect certain fields and on output perhaps
// we'd like to include a computed field based on other values that aren't
// in the data model. Also, check out this awesome blog post on struct composition:
// http://attilaolah.eu/2014/09/10/json-and-struct-composition-in-go/
type ArticleRequest struct {
	*Article

	User *UserPayload `json:"user,omitempty"`

	ProtectedID string `json:"id"` // override 'id' json to have more control
}

func (a *ArticleRequest) Bind(r *http.Request) error {
	// a.Article is nil if no Article fields are sent in the request. Return an
	// error to avoid a nil pointer dereference.
	if a.Article == nil {
		return errors.New("missing required Article fields.")
	}

	// a.User is nil if no Userpayload fields are sent in the request. In this app
	// this won't cause a panic, but checks in this Bind method may be required if
	// a.User or further nested fields like a.User.Name are accessed elsewhere.

	// just a post-process after a decode..
	a.ProtectedID = ""                                 // unset the protected ID
	a.Article.Title = strings.ToLower(a.Article.Title) // as an example, we down-case
	return nil
}

// ArticleResponse is the response payload for the Article data model.
// See NOTE above in ArticleRequest as well.
//
// In the ArticleResponse object, first a Render() is called on itself,
// then the next field, and so on, all the way down the tree.
// Render is called in top-down order, like a http handler middleware chain.

View on GitHub (pinned to 8b258c7bb2)

Solutions

  1. Send a JSON body that includes at least one Article field, e.g. {"title":"hello"} for POST /articles.
  2. If your payload is nested under a wrapper key, unwrap it so the decoder maps fields directly onto ArticleRequest's embedded *Article.
  3. Set Content-Type: application/json and encode the body as JSON rather than form data, since render.Bind relies on the request content type.
  4. If you want the request to be optional, change the Bind check to supply a default *Article instead of returning an error.

Example fix

// before
curl -X POST http://localhost:3333/articles -d '{}'
# -> 400 "missing required Article fields."

// after
curl -X POST http://localhost:3333/articles \
  -H 'Content-Type: application/json' \
  -d '{"title":"awesomeness"}'
# -> 201 {"id":"97","title":"awesomeness"}
Defensive patterns

Strategy: validation

Validate before calling

// Validate the payload shape BEFORE posting so render.Bind never sees an empty Article.
type articleBody struct {
    Title  string `json:"title"`
    UserID int64  `json:"user_id"`
}

func validateArticleBody(b []byte) error {
    var body articleBody
    if err := json.Unmarshal(b, &body); err != nil {
        return fmt.Errorf("invalid JSON: %w", err)
    }
    if strings.TrimSpace(body.Title) == "" {
        return errors.New("missing required Article fields")
    }
    return nil
}

// usage
if err := validateArticleBody(rawBody); err != nil { return err }

Type guard

// Guard the embedded pointer the same way Bind does, before touching fields.
func hasArticle(a *ArticleRequest) bool { return a != nil && a.Article != nil }

if !hasArticle(data) {
    return errors.New("missing required Article fields")
}

Try / catch

// In the handler, treat the Bind error as a 400 and surface ErrorText to the client.
if err := render.Bind(r, data); err != nil {
    // err.Error() == "missing required Article fields."
    _ = render.Render(w, r, ErrInvalidRequest(err)) // 400 with ErrorText
    return
}

Prevention

When it happens

Trigger: POST /articles with an empty body, or a body like {} or {"user":{...}} that omits every Article field (id/title/user_id/slug). Also PUT /articles/{id} when the JSON carries only non-Article fields. Any request that decodes into ArticleRequest without populating the embedded *Article will trip it during render.Bind in CreateArticle (main.go:157) or UpdateArticle (main.go:190).

Common situations: Clients sending a JSON object that wraps the article under a key (e.g. {"article":{...}}) instead of flat fields; clients posting form-encoded data while the route expects JSON; integration tests that reuse an empty struct; a frontend that omits title because the field is optional in its own model but required server-side here.

Related errors


AI-assisted analysis of go-chi/chi@8b258c7bb2 (2026-08-04). Data as JSON: /data/errors/37a688bd7417edbf.json. Report an issue: GitHub.