{"record":{"id":"4418ad4a42e63e99","repo":"iflytek/astron-agent","slug":"max-retries-must-be-non-negative","errorCode":null,"errorMessage":"max_retries must be non-negative","messagePattern":"max_retries must be non-negative","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"core/knowledge/infra/ragflow/ragflow_utils.py","lineNumber":365,"sourceCode":"    ) -> List[Dict[str, Any]]:\n        \"\"\"\n        Get all chunks after parsing, retrying incomplete search snapshots.\n\n        Each attempt delegates to the canonical fail-closed paginator. RAGFlow\n        API errors and incomplete pagination therefore propagate instead of\n        being misreported as a valid empty document.\n\n        Args:\n            dataset_id: Dataset ID\n            doc_id: Document ID\n            max_retries: Maximum incomplete-snapshot retries (default: 15)\n            retry_delay: Delay between retries in seconds (default: 3.0)\n\n        Returns:\n            Complete chunk list, or an empty list after all empty retries.\n        \"\"\"\n        if max_retries < 0:\n            raise ValueError(\"max_retries must be non-negative\")\n        if retry_delay < 0:\n            raise ValueError(\"retry_delay must be non-negative\")\n\n        doc_info = await get_document_info(dataset_id, doc_id)\n        if doc_info is None:\n            raise RuntimeError(\n                f\"RAGFlow document disappeared before chunk retrieval: doc={doc_id}\"\n            )\n\n        expected_count = RagflowUtils._normalize_expected_chunk_count(\n            doc_info.get(\"chunk_count\")\n        )\n\n        last_visible_count = 0\n        last_chunk_ids: Optional[tuple[str, ...]] = None\n        stable_partial_reads = 0\n        for attempt in range(max_retries + 1):\n            chunks = await fetch_all_document_chunks(dataset_id, doc_id, page_size=100)","sourceCodeStart":347,"sourceCodeEnd":383,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/core/knowledge/infra/ragflow/ragflow_utils.py#L347-L383","documentation":"get_document_chunks validates its retry parameters up front and raises ValueError when max_retries is negative. A negative retry count is meaningless — it would mean performing fewer than zero polling attempts — so the function fails fast rather than silently skipping polling.","triggerScenarios":"Calling get_document_chunks(dataset_id, doc_id, max_retries=-1) (or any negative value), typically from miscomputed config such as retries = limit - used when used > limit.","commonSituations":"Retry budget computed by subtraction going negative; env/config loaded as a negative number; off-by-one sign errors in wrappers around get_document_chunks.","solutions":["Clamp the value before calling: max_retries = max(0, configured_retries)","Fix the computation that produced the negative retry budget","Validate config values at load time so negatives are rejected early","Pass the documented defaults (max_retries positive, retry_delay 3.0) instead of hand-rolled values"],"exampleFix":"// before\nchunks = await get_document_chunks(ds, doc_id, max_retries=remaining)\n// after\nchunks = await get_document_chunks(ds, doc_id, max_retries=max(0, remaining))","handlingStrategy":"validation","validationCode":"def safe_max_retries(v) -> int:\n    n = int(v) if v is not None else 3\n    if n < 0:\n        raise ValueError(\"max_retries must be >= 0\")\n    return n\n\nchunks = await get_document_chunks(ds, doc_id, max_retries=safe_max_retries(cfg_retries))","typeGuard":"def is_valid_max_retries(v) -> bool:\n    return isinstance(v, int) and not isinstance(v, bool) and v >= 0","tryCatchPattern":"try:\n    chunks = await get_document_chunks(ds, doc_id, max_retries=n)\nexcept ValueError as e:\n    logger.error(\"bad retry config: %s\", e)\n    chunks = await get_document_chunks(ds, doc_id)  # fall back to defaults","preventionTips":["Clamp computed retry budgets with max(0, value)","Validate retry config at startup, not at call time","Avoid deriving counts by raw subtraction that can go negative","Use constants/defaults instead of ad-hoc inline values"],"tags":["validation","arguments","ragflow"],"backgroundTag":"argument-out-of-range","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}