fix(api): map internal RetCode values to valid HTTP statuses in build_error_result (#18009)

### Summary

Fixes #17980.
This commit is contained in:
Charles
2026-08-10 11:30:11 +08:00
committed by GitHub
parent 3d41ebdded
commit 42373a8229
2 changed files with 148 additions and 1 deletions

View File

@@ -256,11 +256,39 @@ def get_json_result(code: RetCode = RetCode.SUCCESS, message="success", data=Non
return _safe_jsonify(response)
# Internal RetCode values below 200 collide with the HTTP 1xx (informational) range.
# h11 refuses to send a 1xx status as a final response, so Hypercorn drops the
# connection and the client receives an empty reply instead of the JSON error body.
# Map them to real HTTP statuses; the body keeps the original RetCode.
RET_CODE_TO_HTTP_STATUS = {
RetCode.EXCEPTION_ERROR: 500,
RetCode.ARGUMENT_ERROR: 400,
RetCode.DATA_ERROR: 400,
RetCode.OPERATING_ERROR: 400,
RetCode.CONNECTION_ERROR: 500,
RetCode.RUNNING: 500,
RetCode.PERMISSION_ERROR: 403,
# Dify's external knowledge API expects HTTP 403 for authorization failures.
RetCode.AUTHENTICATION_ERROR: 403,
}
def build_error_result(code=RetCode.FORBIDDEN, message="success"):
response = {"code": code, "message": message}
response = _safe_jsonify(response)
if hasattr(response, "status_code"):
response.status_code = code
ret_code = int(code)
http_status = RET_CODE_TO_HTTP_STATUS.get(ret_code)
# The status logs below carry the ret code only; `message` can hold user input.
if http_status is not None:
logging.debug("build_error_result: ret code %s mapped to HTTP %s", ret_code, http_status)
elif 200 <= ret_code <= 599:
http_status = ret_code
logging.debug("build_error_result: ret code %s used as HTTP status", ret_code)
else:
http_status = 500
logging.warning("build_error_result: unmapped ret code %s, falling back to HTTP 500", ret_code)
response.status_code = http_status
return response