From 3df9780c0286ff89a5d94be078b62db0b15cf895 Mon Sep 17 00:00:00 2001 From: Milan Date: Thu, 23 Apr 2026 00:12:30 +0300 Subject: [PATCH] fix(core_helpers): make redact_nested_match_and_regex_keys iterative Replace recursive `_walk` helper with a stack-based traversal so the recursive_detector CI check passes without adding to the ignore list, and avoid Python recursion limits on deeply nested payloads. Made-with: Cursor --- litellm/litellm_core_utils/core_helpers.py | 30 ++++++++++++---------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/litellm/litellm_core_utils/core_helpers.py b/litellm/litellm_core_utils/core_helpers.py index 07239a68869..b7a8b6f9ad7 100644 --- a/litellm/litellm_core_utils/core_helpers.py +++ b/litellm/litellm_core_utils/core_helpers.py @@ -454,20 +454,24 @@ def redact_nested_match_and_regex_keys( except Exception: return payload - def _walk(node: Any) -> None: - if isinstance(node, dict): - if "match" in node: - node["match"] = "[REDACTED]" - if "regex" in node: - node["regex"] = "[REDACTED]" - for value in node.values(): - _walk(value) - elif isinstance(node, list): - for item in node: - _walk(item) - + # Iterative traversal; `seen` guards against cyclic refs preserved by deepcopy. try: - _walk(redacted) + seen: set = set() + stack: List[Any] = [redacted] + while stack: + node = stack.pop() + node_id = id(node) + if node_id in seen: + continue + seen.add(node_id) + if isinstance(node, dict): + if "match" in node: + node["match"] = "[REDACTED]" + if "regex" in node: + node["regex"] = "[REDACTED]" + stack.extend(node.values()) + elif isinstance(node, list): + stack.extend(node) except Exception: return payload return redacted