{"record":{"id":"0962d7bb66047d24","repo":"redis/redis-py","slug":"enx-requires-one-of-ex-px-exat","errorCode":null,"errorMessage":"``enx`` requires one of ``ex``, ``px``, ``exat``, or ``pxat``.","messagePattern":"``enx`` requires one of ``ex``, ``px``, ``exat``, or ``pxat``\\.","errorType":"validation","errorClass":"DataError","httpStatus":null,"severity":"error","filePath":"redis/commands/core.py","lineNumber":3501,"sourceCode":"        ):\n            raise DataError(\"``byfloat`` and ``byint`` are mutually exclusive.\")\n\n        if not at_most_one_value_set(\n            (\n                ex is not None,\n                px is not None,\n                exat is not None,\n                pxat is not None,\n                persist,\n            )\n        ):\n            raise DataError(\n                \"``ex``, ``px``, ``exat``, ``pxat``, \"\n                \"and ``persist`` are mutually exclusive.\"\n            )\n\n        if enx and ex is None and px is None and exat is None and pxat is None:\n            raise DataError(\n                \"``enx`` requires one of ``ex``, ``px``, ``exat``, or ``pxat``.\"\n            )\n\n        pieces: list[EncodableT] = [name]\n\n        if byfloat is not None:\n            pieces.extend((\"BYFLOAT\", byfloat))\n        elif byint is not None:\n            pieces.extend((\"BYINT\", byint))\n\n        if lbound is not None:\n            pieces.extend((\"LBOUND\", lbound))\n        if ubound is not None:\n            pieces.extend((\"UBOUND\", ubound))\n        if saturate:\n            pieces.append(\"SATURATE\")\n\n        pieces.extend(extract_expire_flags(ex, px, exat, pxat))","sourceCodeStart":3483,"sourceCodeEnd":3519,"githubUrl":"https://github.com/redis/redis-py/blob/6a6b581b48225afa0b76912d1028c6035baee932/redis/commands/core.py#L3483-L3519","documentation":"Raised as a `DataError` by `increx()` (redis/commands/core.py:3500) when `enx=True` is set but none of `ex`, `px`, `exat`, `pxat` is provided. The `enx` flag means 'apply expiration only when the key has no existing TTL' — it is meaningless without an expiration to apply.","triggerScenarios":"`r.increx('c', byint=1, enx=True)` with no expiry kwarg.","commonSituations":"Setting `enx` from a config flag without also resolving a TTL; assuming `enx` alone implies a default expiry; building conditional-TTL logic that drops the TTL value in some branch.","solutions":["Always pair `enx=True` with exactly one of `ex`/`px`/`exat`/`pxat`.","If you have no TTL to set, drop `enx` entirely.","Validate that your TTL variable is non-None before enabling `enx`."],"exampleFix":"// before\nr.increx('c', byint=1, enx=True)  # no expiry supplied\n// after\nr.increx('c', byint=1, ex=60, enx=True)  # set 60s TTL only if none exists","handlingStrategy":"validation","validationCode":"if enx and ex is None and px is None and exat is None and pxat is None:\n    raise ValueError('increx: enx requires one of ex/px/exat/pxat')\nr.increx('c', byint=1, ex=ex, enx=enx)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat enx as a modifier on a resolved TTL, not a standalone flag.","Gate enx on having a non-None TTL upstream."],"tags":["increx","arguments","validation","expiry","enx","dataerror"],"backgroundTag":null,"analyzedSha":"6a6b581b48225afa0b76912d1028c6035baee932","analyzedAt":"2026-08-10T12:52:44.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}