{"record":{"id":"f506fc3c83a4f904","repo":"crowdsecurity/crowdsec","slug":"missing-w","errorCode":null,"errorMessage":"missing: %w","messagePattern":"missing: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/apiserver/middlewares/v1/jwt.go","lineNumber":136,"sourceCode":"\t}\n\n\tret.scenariosInput = loginInput.Scenarios\n\n\treturn &ret, nil\n}\n\nfunc (j *JWT) authPlain(c *gin.Context) (*authInput, error) {\n\tvar (\n\t\tloginInput models.WatcherAuthRequest\n\t\terr        error\n\t)\n\n\tctx := c.Request.Context()\n\n\tret := authInput{}\n\n\tif err = c.ShouldBindJSON(&loginInput); err != nil {\n\t\treturn nil, fmt.Errorf(\"missing: %w\", err)\n\t}\n\n\tif err = loginInput.Validate(strfmt.Default); err != nil {\n\t\treturn nil, err\n\t}\n\n\tret.machineID = *loginInput.MachineID\n\tpassword := *loginInput.Password\n\tret.scenariosInput = loginInput.Scenarios\n\n\tret.clientMachine, err = j.DbClient.Ent.Machine.Query().\n\t\tWhere(machine.MachineId(ret.machineID)).\n\t\tFirst(ctx)\n\tif err != nil {\n\t\tlog.Infof(\"Error machine login for %s : %+v \", ret.machineID, err)\n\t\treturn nil, err\n\t}\n","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/apiserver/middlewares/v1/jwt.go#L118-L154","documentation":"authPlain requires a JSON login body (machine_id + password). ShouldBindJSON failed — missing, empty, or malformed body — and the error is tersely wrapped as 'missing: %w'. It is the password-auth counterpart of the TLS scenarios binding error.","triggerScenarios":"Authenticator -> authPlain: POST /api/v1/watchers/login with no body, invalid JSON, wrong Content-Type, or missing machine_id/password fields so gin's JSON binding fails and returns 'missing: <binding error>'.","commonSituations":"Scripts using wrong Content-Type (form instead of JSON); empty curl -d ''; credentials file not loaded by the agent (empty machine_id/password); load balancer or proxy stripping the body on POST.","solutions":["POST valid JSON with Content-Type: application/json: {\"machine_id\":\"...\",\"password\":\"...\"}","Check the agent's local credentials file (/etc/crowdsec/local_api_credentials.yaml) is populated and the agent uses it","Test manually: curl -H 'Content-Type: application/json' -d '{\"machine_id\":\"x\",\"password\":\"y\"}' https://lapi:8080/api/v1/watchers/login','Inspect any proxy/LB config that could drop or rewrite the request body"],"exampleFix":"// before\ncurl -X POST https://lapi:8080/api/v1/watchers/login\n// after\ncurl -H 'Content-Type: application/json' -d '{\"machine_id\":\"myagent\",\"password\":\"secret\"}' -X POST https://lapi:8080/api/v1/watchers/login","handlingStrategy":"validation","validationCode":"// build and validate the login payload before the request\nlogin := struct {\n    MachineID string `json:\"machine_id\"`\n    Password  string `json:\"password\"`\n}{machineID, password}\nif login.MachineID == \"\" || login.Password == \"\" {\n    return errors.New(\"machine_id and password are required\")\n}\nbody, _ := json.Marshal(login)","typeGuard":null,"tryCatchPattern":"resp, err := http.Post(lapiURL+\"/api/v1/watchers/login\", \"application/json\", bytes.NewReader(body))\nif err != nil {\n    return fmt.Errorf(\"password login failed, check JSON body and content-type: %w\", err)\n}","preventionTips":["Always send Content-Type: application/json with machine_id and password fields","Verify local_api_credentials.yaml is populated before starting password-auth watchers","Check proxies/LBs do not strip or rewrite POST bodies","Guard credential loading: fail fast if machine_id/password resolve to empty strings"],"tags":["auth","http","request-binding","json","go"],"backgroundTag":"schema-validation-failed","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}