{"record":{"id":"c7117076d08a332a","repo":"redis/redis-py","slug":"ex-px-exat-pxat-and-keepttl","errorCode":null,"errorMessage":"``ex``, ``px``, ``exat``, ``pxat``, and ``keepttl`` are mutually exclusive.","messagePattern":"``ex``, ``px``, ``exat``, ``pxat``, and ``keepttl`` are mutually exclusive\\.","errorType":"validation","errorClass":"DataError","httpStatus":null,"severity":"error","filePath":"redis/commands/core.py","lineNumber":3884,"sourceCode":"            specified in unix time.\n\n        ``keepttl`` if True, retain the time to live associated with the keys.\n\n        Returns the number of fields that were added.\n\n        Available since Redis 8.4\n        For more information, see https://redis.io/commands/msetex\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                keepttl,\n            )\n        ):\n            raise DataError(\n                \"``ex``, ``px``, ``exat``, ``pxat``, \"\n                \"and ``keepttl`` are mutually exclusive.\"\n            )\n\n        exp_options: list[EncodableT] = []\n        if data_persist_option:\n            exp_options.append(data_persist_option.value)\n\n        exp_options.extend(extract_expire_flags(ex, px, exat, pxat))\n\n        if keepttl:\n            exp_options.append(\"KEEPTTL\")\n\n        pieces = [\"MSETEX\", len(mapping)]\n\n        for pair in mapping.items():\n            pieces.extend(pair)\n","sourceCodeStart":3866,"sourceCodeEnd":3902,"githubUrl":"https://github.com/redis/redis-py/blob/6a6b581b48225afa0b76912d1028c6035baee932/redis/commands/core.py#L3866-L3902","documentation":"Raised as a `DataError` by `msetex()` (redis/commands/core.py:3875) via `at_most_one_value_set(...)` when more than one of `ex`, `px`, `exat`, `pxat`, or `keepttl` is set. MSETEX (Redis 8.4+) applies one TTL policy across the whole key/value mapping; mixing them is rejected client-side.","triggerScenarios":"`r.msetex({'a': 1, 'b': 2}, ex=10, keepttl=True)`, or any MSETEX call combining two or more expiry kwargs.","commonSituations":"Shared expiry helpers reused across SET/MSETEX; config objects carrying both a TTL and a keepttl flag; refactoring that leaves stale kwargs in place.","solutions":["Set exactly one of `ex`, `px`, `exat`, `pxat`, or `keepttl=True`.","Resolve a single TTL policy before calling and forward only that kwarg.","Validate with the same `at_most_one_value_set` helper if you wrap MSETEX."],"exampleFix":"// before\nr.msetex({'a': 1, 'b': 2}, ex=10, keepttl=True)\n// after\nr.msetex({'a': 1, 'b': 2}, ex=10)  # 10s TTL on both keys","handlingStrategy":"validation","validationCode":"expiry = [a for a in (ex, px, exat, pxat) if a is not None]\nif len(expiry) + (1 if keepttl else 0) > 1:\n    raise ValueError('msetex: at most one of ex/px/exat/pxat/keepttl')\nr.msetex(mapping, **({} if not expiry else {'ex': expiry[0]}), keepttl=keepttl)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Forward a single resolved TTL to MSETEX.","Never combine keepttl with a new expiry in shared helpers."],"tags":["msetex","arguments","validation","expiry","dataerror","redis-8-4"],"backgroundTag":null,"analyzedSha":"6a6b581b48225afa0b76912d1028c6035baee932","analyzedAt":"2026-08-10T12:52:44.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}