{"record":{"id":"f8eb4de3ffe52025","repo":"deepset-ai/haystack","slug":"min-keep-steps-must-be-at-least-0-got-min-keep","errorCode":null,"errorMessage":"`min_keep_steps` must be at least 0, got {min_keep_steps}.","messagePattern":"`min_keep_steps` must be at least 0, got (.+?)\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"haystack/hooks/compaction/sliding_window.py","lineNumber":239,"sourceCode":"        tools=[web_search],\n        hooks={\"before_llm\": [hook]},\n    )\n    ```\n    \"\"\"\n\n    def __init__(self, *, min_keep_steps: int = 1, omission_note: str | None = _DEFAULT_OMISSION_NOTE) -> None:\n        \"\"\"\n        Initialize the compactor.\n\n        :param min_keep_steps: The fewest complete recent Agent steps to keep even when they exceed the target. A step\n            is an assistant message and all immediately following tool results. `0` allows all completed steps to be\n            removed when none fit.\n        :param omission_note: The user message left in place of what was removed, or None to remove the messages\n            silently. Include `{num_removed}` to have the number of removed messages substituted in.\n        :raises ValueError: If `min_keep_steps` is negative.\n        \"\"\"\n        if min_keep_steps < 0:\n            raise ValueError(f\"`min_keep_steps` must be at least 0, got {min_keep_steps}.\")\n        self.min_keep_steps = min_keep_steps\n        self.omission_note = omission_note\n\n    def compact(\n        self, messages: list[ChatMessage], target_tokens: int, token_counter: TokenCounter\n    ) -> list[ChatMessage] | None:\n        \"\"\"\n        Drop older history while preserving the task anchor and a complete recent conversation window.\n\n        :param messages: The conversation to compact, oldest to newest.\n        :param target_tokens: The size the kept conversation should come in under.\n        :param token_counter: The `TokenCounter` to measure messages with.\n        :returns: The conversation that survived, with an omission note if configured standing where the removed\n            messages used to sit; or None when there is nothing to remove but an earlier note.\n        \"\"\"\n        if token_counter.count(messages=messages) <= target_tokens:\n            return None\n        kept, note_index, removable = _task_and_step_split(","sourceCodeStart":221,"sourceCodeEnd":257,"githubUrl":"https://github.com/deepset-ai/haystack/blob/e318778c9bf60a1963e3b5f451359655dd696c30/haystack/hooks/compaction/sliding_window.py#L221-L257","documentation":"SlidingWindowCompactor validates min_keep_steps in __init__ (haystack/hooks/compaction/sliding_window.py:239) and rejects negative values with ValueError. min_keep_steps controls how many recent conversation steps are always retained; a negative count is meaningless.","triggerScenarios":"Constructing SlidingWindowCompactor with min_keep_steps < 0, e.g. min_keep_steps=-1, typically from a subtraction or a bad config value.","commonSituations":"Computing min_keep_steps as (desired - something) that goes negative; loading a negative value from YAML/JSON config; off-by-one in defaults.","solutions":["Pass min_keep_steps >= 0, e.g. min_keep_steps=2.","Clamp before construction: min_keep_steps = max(0, configured_value).","Fix the config source if it supplies negative values."],"exampleFix":"// before\ncompactor = SlidingWindowCompactor(min_keep_steps=-1)\n// after\ncompactor = SlidingWindowCompactor(min_keep_steps=max(0, configured_keep))","handlingStrategy":"validation","validationCode":"def validate_min_keep_steps(v):\n    if not isinstance(v, int) or v < 0:\n        raise ValueError(f\"min_keep_steps must be >= 0, got {v!r}\")\nvalidate_min_keep_steps(cfg[\"min_keep_steps\"])","typeGuard":"def is_non_negative_int(v) -> bool:\n    return isinstance(v, int) and not isinstance(v, bool) and v >= 0","tryCatchPattern":"try:\n    compactor = SlidingWindowCompactor(min_keep_steps=n)\nexcept ValueError as e:\n    logger.error(\"bad min_keep_steps: %s\", e)\n    compactor = SlidingWindowCompactor(min_keep_steps=0)","preventionTips":["Clamp computed values with max(0, value)","Validate YAML/JSON config at load time","Prefer explicit positive defaults in config templates"],"tags":["validation","constructor","config","compaction"],"backgroundTag":"invalid-constructor-argument","analyzedSha":"e318778c9bf60a1963e3b5f451359655dd696c30","analyzedAt":"2026-08-30T11:45:20.711Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}