{
  "id": "xnack",
  "title": "XNACK",
  "url": "https://redis.io/docs/latest/commands/xnack/",
  "summary": "Releases pending messages back to the group's PEL without acknowledging them, making them available for re-delivery.",
  "tags": [
    "docs",
    "develop",
    "stack",
    "oss",
    "rs",
    "rc",
    "oss",
    "kubernetes",
    "clients"
  ],
  "last_updated": "2026-05-25T10:30:01-07:00",
  "page_type": "content",
  "content_hash": "14aac9c3ffd559b8745d5873dc57e3d7b5b9d5cfec5a03a7bd8058ec33583abe",
  "sections": [
    {
      "id": "overview",
      "title": "Overview",
      "role": "overview",
      "text": "In the context of a stream consumer group, this command allows a consumer to explicitly release pending messages back to the group's Pending Entries List (PEL) without acknowledging them. Released messages become immediately available for re-delivery to other consumers in the group, eliminating the idle-timeout delay normally required for message recovery.\n\nThis is particularly useful in scenarios such as graceful consumer shutdown, consumer-side failures, resource constraints, or poison message detection. The command provides three different modes that control how the delivery counter is adjusted, giving consumers fine-grained control over retry semantics."
    },
    {
      "id": "required-arguments",
      "title": "Required arguments",
      "role": "content",
      "text": "<details open><summary><code>key</code></summary>\n\nName of the stream.\n\n</details>\n\n<details open><summary><code>group</code></summary>\n\nName of the consumer group.\n\n</details>\n\n<details open><summary><code>mode</code></summary>\n\nControls the delivery counter adjustment. Must be one of:\n\n- **SILENT**: Decrements the delivery counter by 1, essentially \"undoing\" the delivery increment. Use this for an internal failure on the consumer side while processing the message or graceful shutdown where the delivery \"didn't count\".\n- **FAIL**: Keeps the current delivery counter value unchanged. Use this when the current consumer failed to process this message (for example, due to memory constraints). The root cause may be the message or the consumer (it is unclear), so the best strategy would be to let another consumer try to process the message.\n- **FATAL**: Sets the delivery counter to the maximum value (LLONG_MAX or ~9.22 X 10<sup>18</sup>), marking the message as permanently failed. Use this for invalid or suspected malicious messages.\n\n</details>\n\n<details open><summary><code>ids</code></summary>\n\nBlock of arguments that specifies the message IDs to release, where `numids` is the number of message IDs that follow, and `id [id ...]` represents the stream entry IDs to be released back to the group.\n\n</details>"
    },
    {
      "id": "optional-arguments",
      "title": "Optional arguments",
      "role": "parameters",
      "text": "<details open><summary><code>RETRYCOUNT</code></summary>\n\nDirectly sets the delivery counter to the specified value, overriding the mode-based adjustment. This gives explicit control over the retry counter regardless of the mode selected. Note: this is an internal argument that should usually not be used by consumers.\n\n</details>\n\n<details open><summary><code>FORCE</code></summary>\n\nCreates new unowned PEL entries for IDs that are not already in the group PEL. Each entry must exist in the stream. When `FORCE` creates an entry, the delivery counter is set to `0` (or to `RETRYCOUNT` if specified, or to `LLONG_MAX` if mode is `FATAL`). Note: this is an internal argument that should usually not be used by consumers.\n\n</details>"
    },
    {
      "id": "examples",
      "title": "Examples",
      "role": "example",
      "text": "<details open>\n<summary><strong>Basic usage with FAIL mode</strong></summary>\n\n[code example]\n\nAfter NACKing, the messages appear with empty consumer in XPENDING:\n\n[code example]\n\n</details>\n\n<details open>\n<summary><strong>Using SILENT mode for graceful shutdown</strong></summary>\n\n[code example]\n\nWith SILENT mode, the delivery counter is decremented, effectively \"undoing\" the delivery.\n\n</details>\n\n<details open>\n<summary><strong>Using FATAL mode for poison messages</strong></summary>\n\n[code example]\n\nThis marks the message as permanently failed by setting the delivery counter to maximum value.\n\n</details>"
    },
    {
      "id": "behavior",
      "title": "Behavior",
      "role": "content",
      "text": "When `XNACK` executes successfully, the entry:\n\n* is marked as unowned (its last consumer is set to an empty string).\n* is assigned a last delivery time of `0`.\n* is placed at the end of the NACKed portion of the PEL.\n* is available for immediate re-delivery via [`XREADGROUP`](https://redis.io/docs/latest/commands/xreadgroup) CLAIM, [`XCLAIM`](https://redis.io/docs/latest/commands/xclaim), or [`XAUTOCLAIM`](https://redis.io/docs/latest/commands/xautoclaim).\n\nThe head of the PEL is reserved for all NACKed messages, ordered as a FIFO list, followed by pending messages that were neither ACKed nor NACKed in their existing order.\n\nNACKed messages are prioritized over other pending messages in the group's PEL, ensuring they are delivered before idle messages during claim operations."
    },
    {
      "id": "notes",
      "title": "Notes",
      "role": "content",
      "text": "- `XNACK` will only process message IDs that exist in the consumer group's PEL. Messages that are not pending will be ignored and not counted in the return value.\n- Released messages occupy a dedicated zone at the head of the PEL (called the *XNACKed portion of the PEL*), ensuring they are prioritized for re-delivery over other pending entries.\n- Released messages have their delivery time set to 0, making them immediately claimable regardless of the `min-idle-time` parameter in claiming commands.\n- Unlike [`XACK`](https://redis.io/docs/latest/commands/xack), this command does not remove messages from the PEL but instead makes them available for other consumers."
    },
    {
      "id": "redis-software-and-redis-cloud-compatibility",
      "title": "Redis Software and Redis Cloud compatibility",
      "role": "content",
      "text": "| Redis<br />Software | Redis<br />Cloud | <span style=\"min-width: 9em; display: table-cell\">Notes</span> |\n|:----------------------|:-----------------|:------|\n| <span title=\"Not supported\">&#x274c; Standard</span><br /><span title=\"Not supported\"><nobr>&#x274c; Active-Active</nobr></span> | <span title=\"Not supported\">&#x274c; Standard</span><br /><span title=\"Not supported\"><nobr>&#x274c; Active-Active</nobr></span> |  |"
    },
    {
      "id": "return-information",
      "title": "Return information",
      "role": "returns",
      "text": "**RESP2:**\n\n[Integer reply](https://redis.io/docs/latest/develop/reference/protocol-spec#integers): The number of messages successfully released back to the group PEL. Messages that are not in the consumer group PEL will not be counted.\n\n**RESP3:**\n\n[Integer reply](https://redis.io/docs/latest/develop/reference/protocol-spec#integers): The number of messages successfully released back to the consumer group PEL. Messages that are not in the consumer group PEL will not be counted."
    },
    {
      "id": "see-also",
      "title": "See also",
      "role": "related",
      "text": "- [`XREADGROUP`](https://redis.io/docs/latest/commands/xreadgroup): Read messages from a consumer group\n- [`XACK`](https://redis.io/docs/latest/commands/xack): Acknowledge processed messages\n- [`XCLAIM`](https://redis.io/docs/latest/commands/xclaim): Claim pending messages from other consumers\n- [`XAUTOCLAIM`](https://redis.io/docs/latest/commands/xautoclaim): Automatically claim idle pending messages\n- [`XPENDING`](https://redis.io/docs/latest/commands/xpending): Inspect pending messages in a consumer group"
    }
  ],
  "examples": [
    {
      "id": "examples-ex0",
      "language": "plaintext",
      "code": "> XADD mystream * field value1\n\"1526569498055-0\"\n> XADD mystream * field value2\n\"1526569498056-0\"\n> XGROUP CREATE mystream mygroup 0\nOK\n> XREADGROUP GROUP mygroup consumer1 STREAMS mystream >\n1) 1) \"mystream\"\n   2) 1) 1) \"1526569498055-0\"\n         2) 1) \"field\"\n            2) \"value1\"\n      2) 1) \"1526569498056-0\"\n         2) 1) \"field\"\n            2) \"value2\"\n> XNACK mystream mygroup FAIL IDS 2 1526569498055-0 1526569498056-0\n(integer) 2",
      "section_id": "examples"
    },
    {
      "id": "examples-ex1",
      "language": "plaintext",
      "code": "> XPENDING mystream mygroup - + 10\n1) 1) \"1526569498055-0\"\n   2) \"\"\n   3) (integer) -1\n   4) (integer) 1\n2) 1) \"1526569498056-0\"\n   2) \"\"\n   3) (integer) -1\n   4) (integer) 1",
      "section_id": "examples"
    },
    {
      "id": "examples-ex2",
      "language": "plaintext",
      "code": "> XNACK mystream mygroup SILENT IDS 1 1526569498055-0\n(integer) 1",
      "section_id": "examples"
    },
    {
      "id": "examples-ex3",
      "language": "plaintext",
      "code": "> XNACK mystream mygroup FATAL IDS 1 1526569498055-0\n(integer) 1",
      "section_id": "examples"
    }
  ]
}
