zylon-ai/private-gpt · error · ValueError
Maximum number of iterations for condensing exceeded.
Error message
Maximum number of iterations for condensing exceeded.
What it means
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.
Source
Thrown at private_gpt/components/chat/processors/chat_history/memory/strategies/condenser.py:476
None,
)
if last_idx is None:
return chat_history
return self._drop_thinking(chat_history[:last_idx]) + chat_history[last_idx:]
async def _condense_from_left(
self,
llm: LLM,
tokenizer_fn: TokenizerFn | None,
chat_history: list[ChatMessage],
max_length: int,
left_tokens: int | None = None,
last_user_tokens: int | None = None,
right_tokens: int | None = None,
iteration: int = 0,
) -> list[ChatMessage]:
if iteration > MAX_CONDENSE_ITERATIONS:
raise ValueError("Maximum number of iterations for condensing exceeded.")
(
left_messages,
last_user_message,
right_messages,
) = await asyncio.to_thread(self._split_conversation, chat_history)
# Compute per-component token counts if not provided by caller
if left_tokens is None or last_user_tokens is None or right_tokens is None:
left_tokens, last_user_tokens, right_tokens = await asyncio.gather(
self._get_messages_tokens(left_messages, tokenizer_fn=tokenizer_fn),
self._get_messages_tokens(last_user_message, tokenizer_fn=tokenizer_fn),
self._get_messages_tokens(right_messages, tokenizer_fn=tokenizer_fn),
)
assert left_tokens is not None
assert last_user_tokens is not None
assert right_tokens is not None
View on GitHub (pinned to 4a030776a3)
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.
Example fix
// before condense: max_length: 512 # tiny budget -> iterations exhausted // after condense: max_length: 4096
Defensive patterns
Strategy: fallback
Validate before calling
estimated = await estimate_token_count(chat_history, tokenizer)
if estimated > 4 * max_length: # far beyond what 2 iterations can compress
chat_history = chat_history[-20:] # pre-trim before condensing Try / catch
try:
condensed = await condenser.condense(history)
except ValueError as e:
if "iterations" in str(e):
return history[-keep_last_n:] # fallback: naive tail truncation keeping a user turn
raise Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- The last user message exceeds the maximum length allowed.
- Condensed chat history exceeds maximum length after applying
- No user messages found in the chat history.
- No user messages found after condensation.
- No last user message found after condensation.
AI-assisted analysis of zylon-ai/private-gpt@4a030776a3 (2026-08-15).
Data as JSON: /api/errors/39a3be1867ec30f7.
Report an issue: GitHub.