{"record":{"id":"e918249a6651c22b","repo":"nats-io/nats-server","slug":"malformed-request","errorCode":null,"errorMessage":"malformed request","messagePattern":"malformed request","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/accounts.go","lineNumber":4375,"sourceCode":"\nfunc handleDeleteRequest(store *DirJWTStore, s *Server, msg []byte, reply string) {\n\tvar accIds []any\n\tvar subj, sysAccName string\n\tif sysAcc := s.SystemAccount(); sysAcc != nil {\n\t\tsysAccName = sysAcc.GetName()\n\t}\n\t// Only operator and operator signing key are allowed to delete\n\tgk, err := jwt.DecodeGeneric(string(msg))\n\tif err == nil {\n\t\tsubj = gk.Subject\n\t\tif store.deleteType == NoDelete {\n\t\t\terr = fmt.Errorf(\"delete must be enabled in server config\")\n\t\t} else if subj != gk.Issuer {\n\t\t\terr = fmt.Errorf(\"not self signed\")\n\t\t} else if _, ok := store.operator[gk.Issuer]; !ok {\n\t\t\terr = fmt.Errorf(\"not trusted\")\n\t\t} else if list, ok := gk.Data[\"accounts\"]; !ok {\n\t\t\terr = fmt.Errorf(\"malformed request\")\n\t\t} else if accIds, ok = list.([]any); !ok {\n\t\t\terr = fmt.Errorf(\"malformed request\")\n\t\t} else {\n\t\t\tfor _, entry := range accIds {\n\t\t\t\tif acc, ok := entry.(string); !ok ||\n\t\t\t\t\tacc == _EMPTY_ || !nkeys.IsValidPublicAccountKey(acc) {\n\t\t\t\t\terr = fmt.Errorf(\"malformed request\")\n\t\t\t\t\tbreak\n\t\t\t\t} else if acc == sysAccName {\n\t\t\t\t\terr = fmt.Errorf(\"not allowed to delete system account\")\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tif err != nil {\n\t\trespondToUpdate(s, reply, _EMPTY_, fmt.Sprintf(\"delete accounts request by %s failed\", subj), err)\n\t\treturn","sourceCodeStart":4357,"sourceCodeEnd":4393,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/accounts.go#L4357-L4393","documentation":"When validating an account-delete operator claim, the resolver requires a 'Data[\"accounts\"]' field listing the account public keys to delete. If that key is absent from the claim's Data map, the request is rejected as 'malformed request'.","triggerScenarios":"Submitting a delete claim whose Data map has no 'accounts' entry — e.g. a claim constructed by hand or by tooling that omits the accounts list.","commonSituations":"Hand-crafted JSON claim payloads; custom automation calling the $JWS.U > account delete subject; nsc version mismatch producing different claim shapes; copy-pasted claim templates missing fields.","solutions":["Include an 'accounts' field (array of account public keys) in the delete claim's Data map.","Regenerate the claim with nsc or the official jwt library so all required fields are populated.","Log/inspect the claim JWT contents (decode it) to confirm Data.accounts exists before publishing."],"exampleFix":"// before\ndata := map[string]any{} // missing accounts\n// after\ndata := map[string]any{\"accounts\": []string{\"AD...\"}}","handlingStrategy":"validation","validationCode":"raw, _ := json.Marshal(data)\nvar m map[string]any\njson.Unmarshal(raw, &m)\nif _, ok := m[\"accounts\"]; !ok {\n    return fmt.Errorf(\"delete claim must include Data.accounts\")\n}","typeGuard":"func hasAccountsList(d map[string]any) ([]any, bool) {\n    list, ok := d[\"accounts\"].([]any)\n    return list, ok\n}","tryCatchPattern":"if err := pushClaim(jwt); err != nil && strings.Contains(err.Error(), \"malformed request\") {\n    decoded, _ := jwt.DecodeClaim()\n    log.Fatalf(\"claim rejected: inspect Data map: %+v\", decoded)\n}","preventionTips":["Use nsc or the official jwt package to build claims, never hand-rolled JSON","Decode and inspect the claim before publishing","Pin nsc/jwt library versions in CI"],"tags":["nats","jwt","operator-claims","validation"],"backgroundTag":"malformed-jwt-claim","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}