{"record":{"id":"923f49d16fbf859c","repo":"nats-io/nats-server","slug":"js-stream-msg-delete-failed","errorCode":"JS_STREAM_MSG_DELETE_FAILED","errorMessage":"message delete not permitted","messagePattern":"message delete not permitted","errorType":"error_code","errorClass":"JSStreamMsgDeleteFailedError","httpStatus":null,"severity":"error","filePath":"server/jetstream_api.go","lineNumber":3598,"sourceCode":"\t\treturn\n\t}\n\n\tmset, err := acc.lookupStream(stream)\n\tif err != nil {\n\t\tresp.Error = NewJSStreamNotFoundError(Unless(err))\n\t\ts.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))\n\t\treturn\n\t}\n\tmset.cfgMu.RLock()\n\tsealed, denyDelete := mset.cfg.Sealed, mset.cfg.DenyDelete\n\tmset.cfgMu.RUnlock()\n\tif sealed {\n\t\tresp.Error = NewJSStreamSealedError()\n\t\ts.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))\n\t\treturn\n\t}\n\tif denyDelete {\n\t\tresp.Error = NewJSStreamMsgDeleteFailedError(errors.New(\"message delete not permitted\"))\n\t\ts.sendAPIErrResponse(ci, acc, subject, reply, string(msg), s.jsonResponse(&resp))\n\t\treturn\n\t}\n\n\tif s.JetStreamIsClustered() {\n\t\ts.jsClusteredMsgDeleteRequest(ci, acc, mset, stream, subject, reply, &req, rmsg)\n\t\treturn\n\t}\n\n\tvar removed bool\n\tif req.NoErase {\n\t\tremoved, err = mset.removeMsg(req.Seq)\n\t} else {\n\t\tremoved, err = mset.eraseMsg(req.Seq)\n\t}\n\tif err != nil {\n\t\tresp.Error = NewJSStreamMsgDeleteFailedError(err, Unless(err))\n\t} else if !removed {","sourceCodeStart":3580,"sourceCodeEnd":3616,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/jetstream_api.go#L3580-L3616","documentation":"A JetStream API error (JS_STREAM_MSG_DELETE_FAILED) returned by the direct message delete request handler when the stream's configuration denies message deletion (DenyDelete). Even though the request is well-formed, the stream policy forbids removing individual messages, so the server rejects it with this explicit 'message delete not permitted' error.","triggerScenarios":"Sending $JS.API.STREAM.MSG.DELETE.<stream> (DirectDelete or plain) for a stream whose StreamConfig has DenyDelete: true; denyDelete is computed from the stream config and short-circuits before clustered/plain delete processing.","commonSituations":"Deleting messages from a stream created with DenyDelete for compliance/audit reasons; config drift where a stream was recreated with DenyDelete after tooling was written; copy/paste of stream configs between environments.","solutions":["Recreate/update the stream with DenyDelete: false if deletion is intended.","Use stream purge or limit-based retention instead of per-message delete on DenyDelete streams.","Choose a different stream (or a mirror with permissive policy) for deletable data.","Check stream config with StreamInfo before issuing deletes and handle the denial gracefully."],"exampleFix":"// before\n_, err := js.DeleteMsg(\"AUDIT\", 42) // DenyDelete stream\n// after\nsi, _ := js.StreamInfo(\"AUDIT\")\nif si.Config.DenyDelete {\n    return fmt.Errorf(\"stream AUDIT denies message deletion\")\n}\n_, err := js.DeleteMsg(\"AUDIT\", 42)","handlingStrategy":"validation","validationCode":"si, err := js.StreamInfo(name)\nif err != nil { return err }\nif si.Config.DenyDelete { return fmt.Errorf(\"stream %s denies message delete\", name) }\n","typeGuard":"func canDeleteMsgs(si *nats.StreamInfo) bool { return si != nil && !si.Config.DenyDelete }","tryCatchPattern":"_, err := js.DeleteMsg(name, seq)\nvar apiErr *nats.APIError\nif errors.As(err, &apiErr) && apiErr.ErrorCode == nats.JSStreamMsgDeleteFailed {\n    // denied by DenyDelete; surface as policy error, not retryable\n    return fmt.Errorf(\"delete not permitted on %s: %w\", name, err)\n}","preventionTips":["Check StreamInfo().Config.DenyDelete before delete workflows","Align stream templates across environments so DenyDelete matches expectations","Document deletion policy per stream for tooling authors","Prefer retention limits over per-message deletes on restricted streams"],"tags":["jetstream","permissions","stream-config","message-delete"],"backgroundTag":"operation-not-permitted","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}