{"record":{"id":"39a3be1867ec30f7","repo":"zylon-ai/private-gpt","slug":"maximum-number-of-iterations-for-condensing-exceed","errorCode":null,"errorMessage":"Maximum number of iterations for condensing exceeded.","messagePattern":"Maximum number of iterations for condensing exceeded\\.","errorType":"exception","errorClass":"ValueError","httpStatus":400,"severity":"error","filePath":"private_gpt/components/chat/processors/chat_history/memory/strategies/condenser.py","lineNumber":476,"sourceCode":"            None,\n        )\n        if last_idx is None:\n            return chat_history\n        return self._drop_thinking(chat_history[:last_idx]) + chat_history[last_idx:]\n\n    async def _condense_from_left(\n        self,\n        llm: LLM,\n        tokenizer_fn: TokenizerFn | None,\n        chat_history: list[ChatMessage],\n        max_length: int,\n        left_tokens: int | None = None,\n        last_user_tokens: int | None = None,\n        right_tokens: int | None = None,\n        iteration: int = 0,\n    ) -> list[ChatMessage]:\n        if iteration > MAX_CONDENSE_ITERATIONS:\n            raise ValueError(\"Maximum number of iterations for condensing exceeded.\")\n\n        (\n            left_messages,\n            last_user_message,\n            right_messages,\n        ) = await asyncio.to_thread(self._split_conversation, chat_history)\n\n        # Compute per-component token counts if not provided by caller\n        if left_tokens is None or last_user_tokens is None or right_tokens is None:\n            left_tokens, last_user_tokens, right_tokens = await asyncio.gather(\n                self._get_messages_tokens(left_messages, tokenizer_fn=tokenizer_fn),\n                self._get_messages_tokens(last_user_message, tokenizer_fn=tokenizer_fn),\n                self._get_messages_tokens(right_messages, tokenizer_fn=tokenizer_fn),\n            )\n        assert left_tokens is not None\n        assert last_user_tokens is not None\n        assert right_tokens is not None\n","sourceCodeStart":458,"sourceCodeEnd":494,"githubUrl":"https://github.com/zylon-ai/private-gpt/blob/4a030776a31a901ad80b1bf4d7faa2c1a367efbb/private_gpt/components/chat/processors/chat_history/memory/strategies/condenser.py#L458-L494","documentation":"ValueError from ConversationCondenser._condense_from_left. Condensing from the left is recursive with an iteration counter; if it cannot reduce the history below max_length within MAX_CONDENSE_ITERATIONS (=2) passes, it raises instead of looping forever. The guard is `iteration > MAX_CONDENSE_ITERATIONS`, so roughly the third recursive pass fails.","triggerScenarios":"A chat history so long relative to max_length that summarizing the left side twice still exceeds the limit; a very small max_length configuration; token counts not shrinking because summarization returns nearly the same length; LLM summarizer failing to compress.","commonSituations":"max_tokens/max_length set close to the size of a single message; huge pasted documents in history; tokenizer mismatch making estimates not decrease; aggressive context windows set too small for the conversation.","solutions":["Increase the condense max_length (context window budget) so convergence is achievable within 2 iterations.","Trim or drop very old messages before condensing (pre-truncate history length in messages).","Verify the summarizer LLM actually compresses — check its prompt/model; a weak model may paraphrase at full length.","Catch ValueError at the condense call site and fall back to naive truncation of history."],"exampleFix":"// before\ncondense:\n  max_length: 512   # tiny budget -> iterations exhausted\n\n// after\ncondense:\n  max_length: 4096","handlingStrategy":"fallback","validationCode":"estimated = await estimate_token_count(chat_history, tokenizer)\nif estimated > 4 * max_length:  # far beyond what 2 iterations can compress\n    chat_history = chat_history[-20:]  # pre-trim before condensing","typeGuard":null,"tryCatchPattern":"try:\n    condensed = await condenser.condense(history)\nexcept ValueError as e:\n    if \"iterations\" in str(e):\n        return history[-keep_last_n:]  # fallback: naive tail truncation keeping a user turn\n    raise","preventionTips":["Size max_length generously relative to typical histories.","Pre-trim very long histories before condensing.","Verify the summarizer actually compresses (check prompt/model).","Catch non-convergence and fall back to truncation."],"tags":["condensation","iteration-limit","context-window","chat-history","non-convergence"],"backgroundTag":null,"analyzedSha":"4a030776a31a901ad80b1bf4d7faa2c1a367efbb","analyzedAt":"2026-08-15T03:51:26.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}