{"id":"37a688bd7417edbf","repo":"go-chi/chi","slug":"missing-required-article-fields","errorCode":null,"errorMessage":"missing required Article fields.","messagePattern":"missing required Article fields\\.","errorType":"validation","errorClass":"ErrResponse","httpStatus":400,"severity":"error","filePath":"_examples/rest/main.go","lineNumber":331,"sourceCode":"// so you can manage the specific inputs and outputs for clients, and also gives\n// you the opportunity to transform data on input or output, for example\n// on request, we'd like to protect certain fields and on output perhaps\n// we'd like to include a computed field based on other values that aren't\n// in the data model. Also, check out this awesome blog post on struct composition:\n// http://attilaolah.eu/2014/09/10/json-and-struct-composition-in-go/\ntype ArticleRequest struct {\n\t*Article\n\n\tUser *UserPayload `json:\"user,omitempty\"`\n\n\tProtectedID string `json:\"id\"` // override 'id' json to have more control\n}\n\nfunc (a *ArticleRequest) Bind(r *http.Request) error {\n\t// a.Article is nil if no Article fields are sent in the request. Return an\n\t// error to avoid a nil pointer dereference.\n\tif a.Article == nil {\n\t\treturn errors.New(\"missing required Article fields.\")\n\t}\n\n\t// a.User is nil if no Userpayload fields are sent in the request. In this app\n\t// this won't cause a panic, but checks in this Bind method may be required if\n\t// a.User or further nested fields like a.User.Name are accessed elsewhere.\n\n\t// just a post-process after a decode..\n\ta.ProtectedID = \"\"                                 // unset the protected ID\n\ta.Article.Title = strings.ToLower(a.Article.Title) // as an example, we down-case\n\treturn nil\n}\n\n// ArticleResponse is the response payload for the Article data model.\n// See NOTE above in ArticleRequest as well.\n//\n// In the ArticleResponse object, first a Render() is called on itself,\n// then the next field, and so on, all the way down the tree.\n// Render is called in top-down order, like a http handler middleware chain.","sourceCodeStart":313,"sourceCodeEnd":349,"githubUrl":"https://github.com/go-chi/chi/blob/8b258c7bb28f97a5f2a856ff7ef962578fec9215/_examples/rest/main.go#L313-L349","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\ncurl -X POST http://localhost:3333/articles -d '{}'\n# -> 400 \"missing required Article fields.\"\n\n// after\ncurl -X POST http://localhost:3333/articles \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"title\":\"awesomeness\"}'\n# -> 201 {\"id\":\"97\",\"title\":\"awesomeness\"}","handlingStrategy":"validation","validationCode":"// Validate the payload shape BEFORE posting so render.Bind never sees an empty Article.\ntype articleBody struct {\n    Title  string `json:\"title\"`\n    UserID int64  `json:\"user_id\"`\n}\n\nfunc validateArticleBody(b []byte) error {\n    var body articleBody\n    if err := json.Unmarshal(b, &body); err != nil {\n        return fmt.Errorf(\"invalid JSON: %w\", err)\n    }\n    if strings.TrimSpace(body.Title) == \"\" {\n        return errors.New(\"missing required Article fields\")\n    }\n    return nil\n}\n\n// usage\nif err := validateArticleBody(rawBody); err != nil { return err }","typeGuard":"// Guard the embedded pointer the same way Bind does, before touching fields.\nfunc hasArticle(a *ArticleRequest) bool { return a != nil && a.Article != nil }\n\nif !hasArticle(data) {\n    return errors.New(\"missing required Article fields\")\n}","tryCatchPattern":"// In the handler, treat the Bind error as a 400 and surface ErrorText to the client.\nif err := render.Bind(r, data); err != nil {\n    // err.Error() == \"missing required Article fields.\"\n    _ = render.Render(w, r, ErrInvalidRequest(err)) // 400 with ErrorText\n    return\n}","preventionTips":["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."],"tags":["validation","rest","render-bind","json","request-payload","go"],"analyzedSha":"8b258c7bb28f97a5f2a856ff7ef962578fec9215","analyzedAt":"2026-08-04T21:43:11.924Z","schemaVersion":2}