{"record":{"id":"5874fd4195e64e74","repo":"FoundationAgents/MetaGPT","slug":"req-version-should-be-3-9-or-3-10-13","errorCode":null,"errorMessage":"req_version should be (3, 9) or (3, 10, 13)","messagePattern":"req_version should be \\(3, 9\\) or \\(3, 10, 13\\)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"metagpt/utils/common.py","lineNumber":69,"sourceCode":"from metagpt.utils.json_to_markdown import json_to_markdown\n\n\ndef check_cmd_exists(command) -> int:\n    \"\"\"检查命令是否存在\n    :param command: 待检查的命令\n    :return: 如果命令存在，返回0，如果不存在，返回非0\n    \"\"\"\n    if platform.system().lower() == \"windows\":\n        check_command = \"where \" + command\n    else:\n        check_command = \"command -v \" + command + ' >/dev/null 2>&1 || { echo >&2 \"no mermaid\"; exit 1; }'\n    result = os.system(check_command)\n    return result\n\n\ndef require_python_version(req_version: Tuple) -> bool:\n    if not (2 <= len(req_version) <= 3):\n        raise ValueError(\"req_version should be (3, 9) or (3, 10, 13)\")\n    return bool(sys.version_info > req_version)\n\n\nclass OutputParser:\n    @classmethod\n    def parse_blocks(cls, text: str):\n        # 首先根据\"##\"将文本分割成不同的block\n        blocks = text.split(MARKDOWN_TITLE_PREFIX)\n\n        # 创建一个字典，用于存储每个block的标题和内容\n        block_dict = {}\n\n        # 遍历所有的block\n        for block in blocks:\n            # 如果block不为空，则继续处理\n            if block.strip() != \"\":\n                # 将block的标题和内容分开，并分别去掉前后的空白字符\n                block_title, block_content = block.split(\"\\n\", 1)","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/FoundationAgents/MetaGPT/blob/11cdf466d042aece04fc6cfd13b28e1a70341b1f/metagpt/utils/common.py#L51-L87","documentation":"require_python_version(req_version) in metagpt/utils/common.py validates that the req_version tuple has between 2 and 3 components (e.g. (3, 9) or (3, 10, 13)). Passing a 1-tuple like (3,) or a 4-component tuple raises this ValueError before the version comparison runs.","triggerScenarios":"require_python_version((3,)); require_python_version((3, 10, 13, 2)); require_python_version(()) (empty tuple is also outside 2..3).","commonSituations":"Callers constructing the version tuple dynamically (e.g. from a string split on '.') without bounding its length; copy-paste of a full 4-part sys.version_info-like tuple; passing sys.version_info itself is fine (it compares > tuple) but passing a sliced/wrongly-built tuple is not.","solutions":["Pass a 2- or 3-element tuple: require_python_version((3, 10)).","If building from a string, slice it: tuple(map(int, v.split('.')))[:3].","Check the call site and fix the tuple literal that has 1 or 4+ components."],"exampleFix":"# before\nrequire_python_version((3,))  # raises\n\n# after\nrequire_python_version((3, 9))","handlingStrategy":"validation","validationCode":"def valid_version_tuple(v) -> bool:\n    return isinstance(v, tuple) and 2 <= len(v) <= 3 and all(isinstance(x, int) for x in v)","typeGuard":"from typing import Tuple\n\ndef is_req_version(v) -> bool:  # type guard for the API contract\n    return isinstance(v, tuple) and 2 <= len(v) <= 3","tryCatchPattern":null,"preventionTips":["Only pass (major, minor) or (major, minor, patch) tuples.","When parsing a version string, slice to at most 3 parts."],"tags":["metagpt","python-version","validation","api-misuse"],"backgroundTag":null,"analyzedSha":"11cdf466d042aece04fc6cfd13b28e1a70341b1f","analyzedAt":"2026-08-14T23:20:02.994Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}