nats-io/nats-server · error
malformed request
Error message
malformed request
What it means
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'.
Source
Thrown at server/accounts.go:4375
func handleDeleteRequest(store *DirJWTStore, s *Server, msg []byte, reply string) {
var accIds []any
var subj, sysAccName string
if sysAcc := s.SystemAccount(); sysAcc != nil {
sysAccName = sysAcc.GetName()
}
// Only operator and operator signing key are allowed to delete
gk, err := jwt.DecodeGeneric(string(msg))
if err == nil {
subj = gk.Subject
if store.deleteType == NoDelete {
err = fmt.Errorf("delete must be enabled in server config")
} else if subj != gk.Issuer {
err = fmt.Errorf("not self signed")
} else if _, ok := store.operator[gk.Issuer]; !ok {
err = fmt.Errorf("not trusted")
} else if list, ok := gk.Data["accounts"]; !ok {
err = fmt.Errorf("malformed request")
} else if accIds, ok = list.([]any); !ok {
err = fmt.Errorf("malformed request")
} else {
for _, entry := range accIds {
if acc, ok := entry.(string); !ok ||
acc == _EMPTY_ || !nkeys.IsValidPublicAccountKey(acc) {
err = fmt.Errorf("malformed request")
break
} else if acc == sysAccName {
err = fmt.Errorf("not allowed to delete system account")
break
}
}
}
}
if err != nil {
respondToUpdate(s, reply, _EMPTY_, fmt.Sprintf("delete accounts request by %s failed", subj), err)
returnView on GitHub (pinned to 3a66a489d2)
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.
Example fix
// before
data := map[string]any{} // missing accounts
// after
data := map[string]any{"accounts": []string{"AD..."}} Defensive patterns
Strategy: validation
Validate before calling
raw, _ := json.Marshal(data)
var m map[string]any
json.Unmarshal(raw, &m)
if _, ok := m["accounts"]; !ok {
return fmt.Errorf("delete claim must include Data.accounts")
} Type guard
func hasAccountsList(d map[string]any) ([]any, bool) {
list, ok := d["accounts"].([]any)
return list, ok
} Try / catch
if err := pushClaim(jwt); err != nil && strings.Contains(err.Error(), "malformed request") {
decoded, _ := jwt.DecodeClaim()
log.Fatalf("claim rejected: inspect Data map: %+v", decoded)
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- not trusted
- validation errors: %v
- account jwt not found
- auth callout violation: auth callout response is not for exp
- auth callout violation: auth callout response is not for ser
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/e918249a6651c22b.
Report an issue: GitHub.