Redis Error Guide: 'BUSYGROUP Consumer Group name already exists' — Make Group Creation Idempotent
Fix BUSYGROUP Consumer Group name already exists in Redis Streams: understand XGROUP CREATE on restart, MKSTREAM, idempotent group setup, and safe consumer bootstrapping.
- #redis
- #troubleshooting
- #errors
- #streams
Overview
BUSYGROUP Consumer Group name already exists is returned by XGROUP CREATE when you try to create a consumer group on a Redis Stream that already has a group of that name. It is not a corruption or connectivity error — it means the group is already there, usually because your consumer bootstrap runs XGROUP CREATE unconditionally every time it starts.
The literal error clients receive:
(error) BUSYGROUP Consumer Group name already exists
This is the single most common “error” in Redis Streams applications, and it is almost always benign: the correct pattern is to ignore BUSYGROUP, because it simply confirms the group you wanted already exists. The fix is idempotent group creation, not any change to Redis itself.
Symptoms
XGROUP CREATEfails on service startup or on every worker boot.- The stream and group actually work fine once you skip the error.
- Log noise of repeated
BUSYGROUPon scale-up / redeploys.
redis-cli XGROUP CREATE orders g1 0
(error) BUSYGROUP Consumer Group name already exists
redis-cli XINFO GROUPS orders
1) 1) "name"
2) "g1"
3) "consumers"
4) (integer) 3
Common Root Causes
1. Group already created (the normal case)
The service created the group on a previous boot; a later boot tries again.
redis-cli XINFO GROUPS orders | grep -A1 name
"name"
"g1"
The group’s presence is the cause — the create is simply redundant.
2. Multiple workers racing to create the same group
Several consumer instances start together; the first wins, the rest get BUSYGROUP.
redis-cli XINFO GROUPS orders
redis-cli CLIENT LIST | grep -c 'cmd=xgroup'
3. Non-idempotent bootstrap code
The startup path calls XGROUP CREATE without catching BUSYGROUP, so a normal restart surfaces as an error/crash.
# The safe form uses MKSTREAM and ignores BUSYGROUP
redis-cli XGROUP CREATE orders g1 '$' MKSTREAM
4. Confusion between recreating vs. resetting a group
You want to reset the group’s last-delivered ID, but XGROUP CREATE won’t do that on an existing group — you need XGROUP SETID.
redis-cli XINFO GROUPS orders | grep -A1 'last-delivered-id'
Diagnostic Workflow
Step 1: Confirm the group already exists
redis-cli XINFO GROUPS <stream>
Seeing your group name confirms BUSYGROUP is expected, not a fault.
Step 2: Inspect the stream and group state
redis-cli XINFO STREAM <stream>
redis-cli XINFO GROUPS <stream>
1) 1) "name"
2) "g1"
3) "last-delivered-id"
4) "1720000000000-5"
5) "pending"
6) (integer) 12
Step 3: Check for pending / stuck messages
redis-cli XPENDING <stream> <group>
redis-cli XINFO CONSUMERS <stream> <group>
1) (integer) 12
2) "1720000000000-1"
3) "1720000000100-4"
4) 1) 1) "worker-2"
2) "12"
Step 4: Verify the idempotent create pattern works
# This must NOT crash your app; catch BUSYGROUP and continue
redis-cli XGROUP CREATE <stream> <group> '$' MKSTREAM
Step 5: Check the log for how the app handled it
sudo journalctl -u myapp-consumer --no-pager | grep -iE 'BUSYGROUP|XGROUP' | tail
Example Root Cause Analysis
At 08:15 a deploy of the notifications consumer fails its readiness check. The container logs show it crashing on boot with BUSYGROUP Consumer Group name already exists returned from XGROUP CREATE notifications g1 0.
XINFO GROUPS confirms the group is perfectly healthy and already has consumers:
redis-cli XINFO GROUPS notifications
1) 1) "name"
2) "g1"
3) "consumers"
4) (integer) 4
5) "last-delivered-id"
6) "1720003600000-2"
The root cause is purely client-side: the bootstrap treats a redundant XGROUP CREATE as fatal. On a first deploy the group did not exist and the create succeeded; on every deploy since, it correctly returns BUSYGROUP, which the code should swallow. The fix is idempotent group setup:
# Pseudocode bootstrap
try:
XGROUP CREATE notifications g1 $ MKSTREAM
except error as e:
if "BUSYGROUP" not in str(e):
raise # only re-raise real errors
Using MKSTREAM also removes the need to pre-create the stream, and catching BUSYGROUP makes restarts a no-op. After the change, deploys stop failing. If the intent had instead been to re-read from the top, the correct command would have been XGROUP SETID notifications g1 0, not a recreate.
Prevention Best Practices
- Make group creation idempotent: run
XGROUP CREATE ... MKSTREAMand catch/ignoreBUSYGROUP— it means the group exists, which is what you want. - Use
MKSTREAMso the stream is auto-created, avoiding a separate “stream not found” path. - To reset a group’s position, use
XGROUP SETID(not recreate); to remove a stale consumer, useXGROUP DELCONSUMER. - Monitor
XPENDINGand per-consumer pending counts;BUSYGROUPnoise often hides a real backlog problem you should watch instead. - Reclaim stuck messages from dead consumers with
XAUTOCLAIM/XCLAIMrather than recreating the group. - Keep group/stream names in config so multiple workers agree and the create race is harmless.
- Drop consumer logs into the free incident assistant, and see more Redis guides.
Quick Command Reference
# Confirm the group exists (BUSYGROUP is expected)
redis-cli XINFO GROUPS <stream>
redis-cli XINFO STREAM <stream>
# Idempotent create (catch BUSYGROUP in code)
redis-cli XGROUP CREATE <stream> <group> '$' MKSTREAM
# Reset position or remove a consumer instead of recreating
redis-cli XGROUP SETID <stream> <group> 0
redis-cli XGROUP DELCONSUMER <stream> <group> <consumer>
# Backlog / stuck message inspection
redis-cli XPENDING <stream> <group>
redis-cli XINFO CONSUMERS <stream> <group>
redis-cli XAUTOCLAIM <stream> <group> <consumer> 60000 0
Conclusion
BUSYGROUP Consumer Group name already exists is almost always benign: XGROUP CREATE ran against a group that already exists. The typical situations are:
- The group was created on a previous boot (the normal case).
- Multiple workers racing to create the same group at startup.
- Non-idempotent bootstrap code that treats the redundant create as fatal.
- Confusing “recreate” with “reset position” — use
XGROUP SETID.
The fix is client-side idempotency: run XGROUP CREATE ... MKSTREAM and ignore BUSYGROUP. Then spend your monitoring attention on the thing that actually matters — pending/backlog counts via XPENDING and XINFO CONSUMERS.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.