{"record":{"id":"6edfeff1d41c9edf","repo":"cocoindex-io/cocoindex","slug":"operation-name-failed-after-config-max-retries","errorCode":null,"errorMessage":"{operation_name} failed after {config.max_retries + 1} attempts","messagePattern":"(.+?) failed after (.+?) attempts","errorType":"exception","errorClass":"DorisConnectionError","httpStatus":null,"severity":"error","filePath":"python/cocoindex/connectors/doris/_target.py","lineNumber":245,"sourceCode":"        except Exception as e:\n            if not _is_retryable_error(e):\n                raise\n            last_error = e\n            if attempt < config.max_retries:\n                delay = min(\n                    config.base_delay * (config.exponential_base**attempt),\n                    config.max_delay,\n                )\n                _logger.warning(\n                    \"%s failed (attempt %d/%d), retrying in %.1fs: %s\",\n                    operation_name,\n                    attempt + 1,\n                    config.max_retries + 1,\n                    delay,\n                    e,\n                )\n                await asyncio.sleep(delay)\n    raise DorisConnectionError(\n        f\"{operation_name} failed after {config.max_retries + 1} attempts\",\n        host=\"\",\n        port=0,\n        cause=last_error,\n    )\n\n\n# ============================================================\n# Type mapping: Python -> Doris SQL\n# ============================================================\n\n\nclass _TypeMapping(NamedTuple):\n    doris_type: str\n    encoder: ValueEncoder | None = None\n\n\n_LEAF_TYPE_MAPPINGS: dict[type, _TypeMapping] = {","sourceCodeStart":227,"sourceCodeEnd":263,"githubUrl":"https://github.com/cocoindex-io/cocoindex/blob/e84aa99b3292c5270a4b313b2a7137ad9ce8ab3b/python/cocoindex/connectors/doris/_target.py#L227-L263","documentation":"Raised by the Doris connector's _with_retry wrapper when an operation (e.g. Stream Load) still fails after exhausting config.max_retries + 1 attempts. It wraps the last underlying error in a DorisConnectionError, indicating persistent connectivity/availability problems rather than a transient blip.","triggerScenarios":"Calling _stream_load against an unreachable, overloaded, or repeatedly-5xxing Doris FE/BE so every attempt fails and retries are exhausted.","commonSituations":"Wrong host/port or DNS failure; Doris cluster down or restarting; auth failures repeated on every attempt; network partitions in k8s environments; max_retries set too low for a flaky network.","solutions":["Check Doris FE/BE health and connectivity (host, port, firewall, DNS) using curl against the stream-load endpoint.","Inspect the chained `cause` (last_error) for the root failure — auth errors won't fix themselves with retries.","Increase `config.max_retries` and/or backoff if the network is genuinely flaky; otherwise fix the underlying connectivity problem.","Verify credentials and table/label settings so retries aren't doomed from attempt 1."],"exampleFix":"// before\nconfig = DorisConfig(host=\"fe.internal\", max_retries=2)\n// after\nconfig = DorisConfig(host=\"fe.internal\", port=8030, max_retries=5)  # + verify host/port/creds reach Doris","handlingStrategy":"retry","validationCode":"import socket\nsocket.create_connection((config.host, config.port), timeout=5)  # pre-check reachability","typeGuard":null,"tryCatchPattern":"try:\n    app.update()\nexcept DorisConnectionError as e:\n    logger.error(\"Doris op failed permanently: %s\", e.cause)\n    # alert / back off / check cluster health before re-running","preventionTips":["Monitor Doris FE/BE health before large syncs","Set max_retries/backoff appropriate to network reliability","Inspect the chained cause to distinguish auth vs connectivity","Verify host/port/firewall config"],"tags":["doris","network","retry","connection"],"backgroundTag":"request-timeout","analyzedSha":"e84aa99b3292c5270a4b313b2a7137ad9ce8ab3b","analyzedAt":"2026-09-08T15:59:19.997Z","contentChangedAt":"2026-09-08T15:59:19.997Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}