{"id":"635f9eb5d843027f","repo":"redis/redis-py","slug":"both-ignore-max-time-diff-and-ignore-max-val-diff","errorCode":null,"errorMessage":"Both ignore_max_time_diff and ignore_max_val_diff must be set.","messagePattern":"Both ignore_max_time_diff and ignore_max_val_diff must be set\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"redis/commands/timeseries/commands.py","lineNumber":2137,"sourceCode":"        \"\"\"Append EMPTY property to params.\"\"\"\n        if empty:\n            params.append(\"EMPTY\")\n\n    @staticmethod\n    def _append_exclude_empty(params: list[EncodableT], exclude_empty: bool | None):\n        \"\"\"Append EXCLUDEEMPTY property to params.\"\"\"\n        if exclude_empty:\n            params.append(\"EXCLUDEEMPTY\")\n\n    @staticmethod\n    def _append_insertion_filters(\n        params: list[EncodableT],\n        ignore_max_time_diff: int | None = None,\n        ignore_max_val_diff: Number | None = None,\n    ):\n        \"\"\"Append insertion filters to params.\"\"\"\n        if (ignore_max_time_diff is None) != (ignore_max_val_diff is None):\n            raise ValueError(\n                \"Both ignore_max_time_diff and ignore_max_val_diff must be set.\"\n            )\n\n        if ignore_max_time_diff is not None and ignore_max_val_diff is not None:\n            params.extend(\n                [\"IGNORE\", str(ignore_max_time_diff), str(ignore_max_val_diff)]\n            )\n","sourceCodeStart":2119,"sourceCodeEnd":2145,"githubUrl":"https://github.com/redis/redis-py/blob/da03cdc7e8731092b13e395605c3c1fb2de25de1/redis/commands/timeseries/commands.py#L2119-L2145","documentation":"Raised by _append_insertion_filters (used by TS.ADD, TS.MADD, TS.INCRBY, TS.DECRBY) when only one of ignore_max_time_diff / ignore_max_val_diff is set. The IGNORE clause requires both a time threshold and a value threshold together; they are not independently optional. Note this raises ValueError (not DataError).","triggerScenarios":"client.ts().add('key', '*', 1.0, ignore_max_time_diff=100) without ignore_max_val_diff, or the reverse. Both thresholds must be present.","commonSituations":"Enabling the ignore-duplicate threshold for one dimension only; reading thresholds from config where one is missing; assuming the value threshold defaults.","solutions":["Set both thresholds together: client.ts().add('key', '*', 1.0, ignore_max_time_diff=100, ignore_max_val_diff=0.5).","If you do not want the IGNORE clause, omit both arguments.","Note this also requires duplicate_policy='last' server-side for the IGNORE to take effect."],"exampleFix":"// before\nclient.ts().add('key', '*', 1.0, ignore_max_time_diff=100)\n// after\nclient.ts().add('key', '*', 1.0, duplicate_policy='last', ignore_max_time_diff=100, ignore_max_val_diff=0.5)","handlingStrategy":"validation","validationCode":"def normalize_ignore(time_diff, val_diff):\n    if (time_diff is None) != (val_diff is None):\n        raise ValueError(\"Set both ignore_max_time_diff and ignore_max_val_diff, or neither\")\n    return time_diff, val_diff","typeGuard":"def ignore_pair_valid(time_diff, val_diff) -> bool:\n    return (time_diff is None) == (val_diff is None)","tryCatchPattern":"try:\n    client.ts().add('k', '*', 1.0, ignore_max_time_diff=td)\nexcept ValueError:\n    client.ts().add('k', '*', 1.0)  # drop the IGNORE clause","preventionTips":["Always set both ignore thresholds together or omit both.","Remember IGNORE also needs duplicate_policy='last' server-side.","Validate the pair in a helper before TS.ADD/MADD/INCRBY/DECRBY."],"tags":["redistimeseries","timeseries","add","ignore","argument-error"],"analyzedSha":"da03cdc7e8731092b13e395605c3c1fb2de25de1","analyzedAt":"2026-08-04T20:26:47.563Z","schemaVersion":2}