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
- Send a JSON body that includes at least one Article field, e.g. {"title":"hello"} for POST /articles.
- If your payload is nested under a wrapper key, unwrap it so the decoder maps fields directly onto ArticleRequest's embedded *Article.
- Set Content-Type: application/json and encode the body as JSON rather than form data, since render.Bind relies on the request content type.
- 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
- Always include at least one Article field (commonly title) in any POST/PUT body.
- Write a client-side schema test that fails if the JSON does not unmarshal into a non-nil *Article.
- Keep Bind checks in sync with your OpenAPI spec so the contract documents which fields are required.
- Set Content-Type: application/json so render.Bind uses the JSON decoder rather than the form decoder.
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.