{"record":{"id":"0b551e0f0c143d8d","repo":"FoundationAgents/MetaGPT","slug":"fail-to-reduce-message-length","errorCode":null,"errorMessage":"fail to reduce message length","messagePattern":"fail to reduce message length","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"metagpt/utils/text.py","lineNumber":31,"sourceCode":"\n    Args:\n        msgs: A generator of strings representing progressively shorter valid prompts.\n        model_name: The name of the encoding to use. (e.g., \"gpt-3.5-turbo\")\n        system_text: The system prompts.\n        reserved: The number of reserved tokens.\n\n    Returns:\n        The concatenated message segments reduced to fit within the maximum token size.\n\n    Raises:\n        RuntimeError: If it fails to reduce the concatenated message length.\n    \"\"\"\n    max_token = TOKEN_MAX.get(model_name, 2048) - count_output_tokens(system_text, model_name) - reserved\n    for msg in msgs:\n        if count_output_tokens(msg, model_name) < max_token or model_name not in TOKEN_MAX:\n            return msg\n\n    raise RuntimeError(\"fail to reduce message length\")\n\n\ndef generate_prompt_chunk(\n    text: str,\n    prompt_template: str,\n    model_name: str,\n    system_text: str,\n    reserved: int = 0,\n) -> Generator[str, None, None]:\n    \"\"\"Split the text into chunks of a maximum token size.\n\n    Args:\n        text: The text to split.\n        prompt_template: The template for the prompt, containing a single `{}` placeholder. For example, \"### Reference\\n{}\".\n        model_name: The name of the encoding to use. (e.g., \"gpt-3.5-turbo\")\n        system_text: The system prompts.\n        reserved: The number of reserved tokens.\n","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/FoundationAgents/MetaGPT/blob/11cdf466d042aece04fc6cfd13b28e1a70341b1f/metagpt/utils/text.py#L13-L49","documentation":"Raised by metagpt.utils.text.reduce_message_length: it computes a per-model token budget (TOKEN_MAX[model_name] minus system-text tokens minus reserved) and returns the first message that fits; if every candidate message still exceeds the budget, reduction has failed and RuntimeError is raised rather than silently returning an oversized message.","triggerScenarios":"Calling reduce_message_length(msgs, model_name, system_text, reserved) where every msg exceeds TOKEN_MAX[model_name]-2048-style budget, or model_name is unknown AND the first msg is huge (unknown models short-circuit the check via `model_name not in TOKEN_MAX`, but known small-window models like gpt-3.5 hit it), or reserved/system_text consume the whole budget.","commonSituations":"Feeding large documents/logs to a small-context model; system_text plus reserved tokens leaving almost no room; oversized single messages that cannot be trimmed because each candidate is one big blob.","solutions":["Use a model with a larger context window (present in TOKEN_MAX), e.g. a gpt-4-class or claude-class model name.","Shrink the inputs: shorter system_text, smaller reserved value, or pre-truncate/split the messages before calling.","Split the content with generate_prompt_chunk and process it in chunks instead of trying to fit one message.","Ensure msgs are ordered/curated so at least one candidate fits (drop the largest ones)."],"exampleFix":"# before\nmsg = reduce_message_length(msgs, 'gpt-35-turbo', LONG_SYSTEM, reserved=2000)  # RuntimeError\n\n# after\nfrom metagpt.utils.text import generate_prompt_chunk\nfor chunk in generate_prompt_chunk(big_text, PROMPT_TPL, 'gpt-4o', SHORT_SYSTEM):\n    ...  # process each fitting chunk","handlingStrategy":"fallback","validationCode":"from metagpt.utils.token_counter import count_output_tokens\nfrom metagpt.utils.text import TOKEN_MAX\nbudget = TOKEN_MAX.get(model_name, 2048) - count_output_tokens(system_text, model_name) - reserved\nif msgs and count_output_tokens(msgs[-1], model_name) >= budget:\n    raise ValueError('messages exceed model budget; chunk first')","typeGuard":"def fits_in_budget(msg: str, model_name: str, system_text: str, reserved: int = 0) -> bool:\n    if model_name not in TOKEN_MAX:\n        return True\n    budget = TOKEN_MAX[model_name] - count_output_tokens(system_text, model_name) - reserved\n    return count_output_tokens(msg, model_name) < budget","tryCatchPattern":"from metagpt.utils.text import generate_prompt_chunk\ntry:\n    msg = reduce_message_length(msgs, model_name, system_text, reserved)\nexcept RuntimeError:\n    # fall back to chunked processing instead of one oversized message\n    for chunk in generate_prompt_chunk(big_text, template, model_name, system_text):\n        handle(chunk)","preventionTips":["Pick a model whose TOKEN_MAX entry fits system_text + reserved + payload.","Trim system_text and reserved before large payloads.","Chunk long inputs up front with generate_prompt_chunk; don't rely on reduce to shrink untrimmable blobs.","Verify model_name is a known key in TOKEN_MAX before relying on reduction."],"tags":["tokens","context-window","llm","chunking"],"backgroundTag":null,"analyzedSha":"11cdf466d042aece04fc6cfd13b28e1a70341b1f","analyzedAt":"2026-08-14T23:20:02.994Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}