Skip to content

Commit f739359

Browse files
authored
Merge pull request #1013 from lupko/flight-fixes
RELATED: CQ-1268 - add limits to ErrorInfo fields
2 parents d4b73ea + 1e4fbd3 commit f739359

File tree

2 files changed

+45
-8
lines changed

2 files changed

+45
-8
lines changed

gooddata-flight-server/gooddata_flight_server/errors/error_info.py

+34-8
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,29 @@
11
# (C) 2024 GoodData Corporation
22
import base64
33
import traceback
4-
from typing import Callable, Optional, Union
4+
from typing import Callable, Optional, Union, cast
55

66
import orjson
77
import pyarrow.flight
88

99
from gooddata_flight_server.errors.error_code import ErrorCode
1010

11+
_ERROR_INFO_MAX_MSG = 256
12+
_ERROR_INFO_MAX_DETAIL = 512
13+
14+
15+
def _truncate_str_value(val: Optional[str], max_len: int) -> Optional[str]:
16+
if val is None:
17+
return None
18+
19+
if len(val) <= max_len:
20+
return val
21+
22+
# no big deal that the actual max length is slightly exceeded
23+
# all this truncating happens because ErrorInfo is eventually
24+
# passed via gRPC headers which have 16k hard limit
25+
return val[:max_len] + " [truncated]"
26+
1127

1228
class ErrorInfo:
1329
"""
@@ -22,15 +38,15 @@ def __init__(
2238
body: Optional[bytes] = None,
2339
code: int = 0,
2440
) -> None:
25-
self._msg = msg
26-
self._detail: Optional[str] = detail
41+
self._msg = cast(str, _truncate_str_value(msg, _ERROR_INFO_MAX_MSG))
42+
self._detail: Optional[str] = _truncate_str_value(detail, _ERROR_INFO_MAX_DETAIL)
2743
self._body: Optional[bytes] = body
2844
self._code: int = code
2945

3046
@property
3147
def msg(self) -> str:
3248
"""
33-
:return: human readable error message
49+
:return: human-readable error message
3450
"""
3551
return self._msg
3652

@@ -60,26 +76,36 @@ def with_msg(self, msg: str) -> "ErrorInfo":
6076
"""
6177
Updates error message.
6278
63-
:param msg: new message
79+
:param msg: new message, up to 256 characters; will be truncated if the limit is exceeded
6480
:return: self, for call chaining sakes
6581
"""
66-
self._msg = msg
82+
self._msg = cast(str, _truncate_str_value(msg, _ERROR_INFO_MAX_MSG))
83+
6784
return self
6885

6986
def with_detail(self, detail: Optional[str] = None) -> "ErrorInfo":
7087
"""
7188
Updates or resets the error detail.
7289
73-
:param detail: detail to set; if None, the detail stored in the meta will be removed; default is None
90+
:param detail: detail to set; if None, the detail stored in the meta will be removed; default is None;
91+
detail can be up to 512 characters; will be truncated if the limit is exceeded
7492
:return: self, for call chaining sakes
7593
"""
76-
self._detail = detail
94+
self._detail = _truncate_str_value(detail, _ERROR_INFO_MAX_DETAIL)
95+
7796
return self
7897

7998
def with_body(self, body: Optional[Union[bytes, str]]) -> "ErrorInfo":
8099
"""
81100
Updates or resets the error body.
82101
102+
IMPORTANT: the ErrorInfo (and thus the contents of `body`) are passed out via FlightError.extra_info
103+
property. The Flight RPC implementations pass the `extra_info` via gRPC headers. In turn, the gRPC headers
104+
do have size limit. Keep this in mind when designing the value of `body`.
105+
106+
If you set body that is too large, you will run into problems like this:
107+
https://github.com/grpc/grpc/issues/37852.
108+
83109
:param body: body to set; if None, the body stored in the meta will be removed; default is None
84110
:return: self, for call chaining sakes
85111
"""

gooddata-flight-server/tests/errors/error_info.py

+11
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,17 @@ def test_serde_error_info2():
2222
assert deserialized.detail == error.detail
2323

2424

25+
def test_error_info_limits1():
26+
error = ErrorInfo.for_reason(666, "error" * 500).with_detail("detail" * 500)
27+
28+
assert "truncated" in error.msg
29+
assert "truncated" in error.detail
30+
31+
error = ErrorInfo(code=666, msg="error" * 500, detail="detail" * 500)
32+
assert "truncated" in error.msg
33+
assert "truncated" in error.detail
34+
35+
2536
def test_serde_retry_info1():
2637
retry = RetryInfo(
2738
flight_info=None,

0 commit comments

Comments
 (0)