nats-io/nats-server · error
not self signed
Error message
not self signed
What it means
Delete requests on the account resolver must be signed by the account itself (subject == issuer). If the decoded delete JWT's Subject differs from its Issuer — e.g. it was signed by an operator or signing key rather than the account key — the server rejects it with 'not self signed'.
Source
Thrown at server/accounts.go:4371
response := map[string]any{"server": server, "data": accIds}
s.sendInternalMsgLocked(reply, _EMPTY_, server, response)
}
}
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
}
}
}View on GitHub (pinned to 3a66a489d2)
Solutions
- Sign the delete request with the account's own key pair so Issuer equals Subject
- Check nsc/operator setup so the delete is issued from the account context, not the operator
- Verify the JWT (decode and compare subject/issuer) before publishing the delete request
Example fix
// before nsc delete account --sign-with-operator-key ... // operator-signed, rejected // after nsc delete account my-account // signed by the account key itself (issuer == subject)
Defensive patterns
Strategy: validation
Validate before calling
gk, err := jwt.DecodeGeneric(deleteJWT)
if err != nil {
return err
}
if gk.Subject != gk.Issuer {
return fmt.Errorf("delete request must be self-signed (subject %q != issuer %q)", gk.Subject, gk.Issuer)
}
Try / catch
if err := sendDeleteRequest(store, msg); err != nil {
if strings.Contains(err.Error(), "not self signed") {
// re-sign with the account key and resend
}
}
Prevention
- Sign delete requests with the account's own keypair
- Verify subject==issuer in tooling before publishing
- Avoid operator-key signing contexts (nsc) for account deletes
When it happens
Trigger: Publishing a delete request JWT whose issuer is an operator or operator signing key while the subject names an account, so gk.Subject != gk.Issuer; using the wrong nsc/operator context that signs with the operator key.
Common situations: Automation signing delete requests with operator credentials; using an operator-signed delete where account-signed is required; misconfigured nsc signing keys.
Related errors
- will only fetch valid account keys
- store operation not supported for URL Resolver
- could not fetch <%q>: %v
- could not fetch <%q>: no response
- delete must be enabled in server config
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/965fd2a5c77dc2b2.
Report an issue: GitHub.