OtterMind/Chat2DB · error · RequestError
message is too long
Error message
message is too long
What it means
Raised at relay_server.py:227 when len(message) > config.max_message_length. The cap defaults to 900 (RelayConfig.max_message_length) and is read from the RELAY_MAX_MESSAGE_LENGTH environment variable. It protects the QQ/NapCat group message size limit. len() counts Unicode code points, not bytes. Returned as HTTP 400.
Source
Thrown at script/github/qq_relay/relay_server.py:228
payload = json.loads(self.rfile.read(content_length).decode("utf-8"))
except (UnicodeDecodeError, json.JSONDecodeError) as error:
raise RequestError(HTTPStatus.BAD_REQUEST, "request body is not valid JSON") from error
if not isinstance(payload, Mapping):
raise RequestError(HTTPStatus.BAD_REQUEST, "request body must be a JSON object")
return payload
def _validate_payload(self, payload: Mapping[str, Any]) -> tuple[str, str]:
config = self.relay_state.config
if payload.get("repository") != config.repository:
raise RequestError(HTTPStatus.FORBIDDEN, "repository is not allowed")
delivery_id = payload.get("delivery_id")
if not isinstance(delivery_id, str) or not DELIVERY_ID_PATTERN.fullmatch(delivery_id):
raise RequestError(HTTPStatus.BAD_REQUEST, "delivery_id is invalid")
message = payload.get("message")
if not isinstance(message, str) or not message.strip():
raise RequestError(HTTPStatus.BAD_REQUEST, "message must be non-empty text")
if len(message) > config.max_message_length:
raise RequestError(HTTPStatus.BAD_REQUEST, "message is too long")
if CONTROL_CHARACTER_PATTERN.search(message):
raise RequestError(HTTPStatus.BAD_REQUEST, "message contains control characters")
return delivery_id, message
def do_GET(self) -> None: # noqa: N802
if self.path == "/healthz":
self._send_json(HTTPStatus.OK, {"ok": True})
return
self._send_json(HTTPStatus.NOT_FOUND, {"error": "not found"})
def do_POST(self) -> None: # noqa: N802
delivery_id = ""
reserved = False
try:
if self.path != "/v1/qq/github":
raise RequestError(HTTPStatus.NOT_FOUND, "not found")
self._authorize()
delivery_id, message = self._validate_payload(self._read_payload())View on GitHub (pinned to 5ee1e990e7)
Solutions
- Truncate the message to <= max_message_length code points on the sender before posting.
- Raise RELAY_MAX_MESSAGE_LENGTH on the relay to stay within QQ's real limit.
- Split very long content into multiple deliveries with distinct delivery_ids.
Example fix
# before payload["message"] = long_text # after payload["message"] = long_text[:900] # or read RELAY_MAX_MESSAGE_LENGTH from relay
Defensive patterns
Strategy: validation
Validate before calling
max_len = int(os.environ.get('RELAY_MAX_MESSAGE_LENGTH', '900'))
payload['message'] = payload['message'][:max_len] Type guard
def message_within_limit(payload: dict, limit: int) -> bool:
msg = payload.get('message')
return isinstance(msg, str) and len(msg) <= limit Try / catch
resp = requests.post(url, json=payload)
if resp.status_code == 400 and resp.json().get('error') == 'message is too long':
payload['message'] = payload['message'][:900]
resp = requests.post(url, json=payload) Prevention
- Truncate by code points (len on str), not bytes, to match the relay.
- Keep sender's limit in sync with the relay's RELAY_MAX_MESSAGE_LENGTH.
When it happens
Trigger: A single delivery whose message text is longer than the configured cap, e.g. a full commit diff, log dump, or concatenated PR body forwarded as one message.
Common situations: Default 900 is too small for verbose events and RELAY_MAX_MESSAGE_LENGTH was not raised; sender forwards raw artifact text without truncation; emoji/CJK counts as one code point each so byte-based truncation underestimates.
Related errors
- request body must be a JSON object
- repository is not allowed
- delivery_id is invalid
- message must be non-empty text
- message contains control characters
AI-assisted analysis of OtterMind/Chat2DB@5ee1e990e7 (2026-08-14).
Data as JSON: /api/errors/3c119f54e4ab00e8.
Report an issue: GitHub.