Skip to content

rueidiscompat: fix HSetEXWithArgs panic when Condition is unset#1009

Open
jtlang wants to merge 1 commit into
redis:mainfrom
jtlang:fix-hsetexwithargs-condition
Open

rueidiscompat: fix HSetEXWithArgs panic when Condition is unset#1009
jtlang wants to merge 1 commit into
redis:mainfrom
jtlang:fix-hsetexwithargs-condition

Conversation

@jtlang

@jtlang jtlang commented Jul 15, 2026

Copy link
Copy Markdown

Summary

HSetEXWithArgs only built the underlying HSETEX command inside the Condition == HSetEXFNX / Condition == HSetEXFXX branches. Since Condition is optional (per HSetEXOptions), leaving it unset to apply only ExpirationType (e.g. EX/PX/KEEPTTL) left the command builder at its zero value, causing a nil pointer dereference in HsetexFieldValue.FieldValue.

Repro

adapter.HSetEXWithArgs(ctx, "key", &rueidiscompat.HSetEXOptions{
    ExpirationType: rueidiscompat.HSetEXExpirationEX,
    ExpirationVal:  100,
}, "field1", "value1")

panics with invalid memory address or nil pointer dereference in gen_hash.go:HsetexFieldValue.FieldValue.

Fix

Add the missing no-condition path in the Condition switch, building directly off Hsetex().Key(key) (no .Fnx()/.Fxx()). Also added a default case to each ExpirationType switch so an unset expiration falls through to .Fields() instead of leaving the command unset.

Test plan

  • Added a regression test (should HSetEXWithArgs apply ExpirationType without a Condition) in the existing Redis 8.6+ commands suite, covering set + get + TTL round-trip.
  • Verified the new test panics on main (before the fix) and passes after.
  • go build/go vet clean; existing hash-command specs still pass.

Note

Low Risk
Localized fix to Redis hash command adapter command-building; behavior change only affects previously broken call paths.

Overview
Fixes a nil pointer panic in HSetEXWithArgs when HSetEXOptions.Condition is left unset but ExpirationType (e.g. EX) is set—previously only FNX/FXX branches built the HSETEX command.

The adapter now handles the no-condition path by building Hsetex().Key(key) with the appropriate expiration modifiers, and adds default fallbacks on each ExpirationType switch (including FNX/FXX) so the field builder is always initialized before FieldValue runs.

A regression test covers set/get/TTL when only expiration options are provided.

Reviewed by Cursor Bugbot for commit ff969bc. Bugbot is set up for automated code reviews on this repo. Configure here.

HSetEXWithArgs only built the underlying command inside the
Condition == HSetEXFNX / HSetEXFXX branches. Since Condition is
optional, leaving it unset (to apply only ExpirationType) left the
command builder as its zero value, causing a nil pointer dereference
in FieldValue. Add the missing no-condition path, building directly
off Hsetex().Key(key) with no .Fnx()/.Fxx().
@jtlang jtlang changed the title fix: HSetEXWithArgs panics when Condition is unset rueidiscompat: fix HSetEXWithArgs panic when Condition is unset Jul 15, 2026
@rueian

rueian commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

Hi @jtlang, is the new behavior aligned with go-redis?

@jtlang

jtlang commented Jul 16, 2026

Copy link
Copy Markdown
Author

@rueian Yes, this will bring it in line with go-redis behavior

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants