{"record":{"id":"57b3d9adc21ae2ad","repo":"iflytek/astron-agent","slug":"e-message-thirdpartyexception-errorresponse","errorCode":null,"errorMessage":"${e.message} (ThirdPartyException ErrorResponse)","messagePattern":"(.+?) \\(ThirdPartyException ErrorResponse\\)","errorType":"http","errorClass":"ThirdPartyException","httpStatus":null,"severity":"error","filePath":"core/knowledge/api/v1/api.py","lineNumber":141,"sourceCode":"            # Basic types, convert to string for consistent handling\n            span_context.add_info_events({\"usr_output\": str(result_data)})\n        else:\n            # Other types (like custom objects), try to stringify\n            span_context.add_info_events({\"usr_output\": str(result_data)})\n\n        metric.in_success_count()\n\n        return SuccessDataResponse(data=result_data, sid=span_context.sid)\n\n    except ProtocolParamException as e:\n        error_msg = f\"{operation_callable.__name__} ProtocolParamException, reason {e}\"\n        logger.error(error_msg)\n        span_context.record_exception(e)\n        metric.in_error_count(code=CodeEnum.ParameterCheckException.code)\n        return ErrorResponse(code_enum=CodeEnum.ParameterCheckException, message=str(e))\n\n    except ThirdPartyException as e:\n        error_msg = f\"{operation_callable.__name__} err (ThirdParty), reason {e}\"\n        logger.error(error_msg)\n        span_context.record_exception(e)\n        metric.in_error_count(code=e.code)\n        # Create a CodeEnum-like object for the response\n        error_code = type(\"ErrorCode\", (), {\"code\": e.code, \"msg\": e.message})()\n        return ErrorResponse(code_enum=error_code, message=e.message)\n\n    except CustomException as e:\n        error_msg = f\"{operation_callable.__name__} err (Custom), reason {e}\"\n        logger.error(error_msg)\n        span_context.record_exception(e)\n        metric.in_error_count(code=e.code)\n        # Create a CodeEnum-like object for the response\n        error_code = type(\"ErrorCode\", (), {\"code\": e.code, \"msg\": e.message})()\n        return ErrorResponse(code_enum=error_code, message=e.message)\n\n    except Exception as e:  # pylint: disable=W0718\n        # Intentionally catch all exceptions here as part of global exception handling","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/core/knowledge/api/v1/api.py#L123-L159","documentation":"handle_rag_operation in core/knowledge/api/v1/api.py wraps RAG operations (file_split, file_upload, chunk_save, chunk_update, chunk_delete, chunk_query) and catches ThirdPartyException separately. It records the exception on the tracing span, increments an error metric with the exception's own code, builds an ad-hoc CodeEnum-like object from e.code/e.message, and returns an ErrorResponse carrying that code and message. The HTTP response surfaces the third-party failure message directly to the caller.","triggerScenarios":"Any of the six wrapped RAG API calls invokes a downstream dependency (vector store, embedding service, MinIO, model inference) whose adapter raises ThirdPartyException(code, message).","commonSituations":"Vector DB unreachable or rejecting the query; embedding endpoint 4xx/5xx; object storage credentials invalid during file_upload; upstream SDK raising wrapped ThirdPartyException on timeout.","solutions":["Check the message for which third-party dependency failed and verify that service is reachable (network, DNS, credentials)","Verify configuration (endpoints, API keys, bucket names) for the failing dependency in the knowledge service config","Check the tracing span recorded for this request to locate the upstream call that raised","Add retry/circuit-breaker handling in the third-party adapter if failures are transient"],"exampleFix":"// before\nreturn ErrorResponse(code_enum=error_code, message=e.message)\n// after\n# in the adapter, add context before raising\nraise ThirdPartyException(code=e.code, message=f\"milvus search failed: {e.message}\")","handlingStrategy":"try-catch","validationCode":"def precheck_dependency(client):\n    try:\n        client.health_check(timeout=3)\n    except Exception as e:\n        raise PrecheckError(f\"third-party dependency unhealthy: {e}\")","typeGuard":"def is_thirdparty_error(resp: dict) -> bool:\n    return isinstance(resp, dict) and resp.get(\"code\") not in (None, 0) and \"(ThirdParty)\" in str(resp.get(\"message\", \"\"))","tryCatchPattern":"try:\n    resp = rag_api.chunk_query(payload)\nexcept httpx.HTTPError as e:\n    log.warning(\"RAG third-party failure: %s\", e)\n    resp = fallback_response(code=getattr(e, 'code', 503))","preventionTips":["Health-check vector store/embedding/storage dependencies before request processing","Configure sensible connect/read timeouts and retries in third-party adapters","Keep adapter exceptions wrapped in ThirdPartyException with actionable messages","Alert on metric codes emitted by handle_rag_operation"],"tags":["python","fastapi","third-party","rag","error-response"],"backgroundTag":"upstream-api-error","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"}