OtterMind/Chat2DB · error · RequestError

message must be non-empty text

Error message

message must be non-empty text

What it means

Raised at relay_server.py:225 when "message" is missing, not a str, or is whitespace-only (not message.strip()). The relay forwards this text verbatim to the QQ group via OneBot, so it must carry visible content. Returned as HTTP 400.

Source

Thrown at script/github/qq_relay/relay_server.py:226

            raise RequestError(HTTPStatus.REQUEST_ENTITY_TOO_LARGE, "request body is too large")
        try:
            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")

View on GitHub (pinned to 5ee1e990e7)

Solutions

  1. Ensure message is a non-empty string after .strip() before posting.
  2. Render a sensible fallback when the event text is blank.
  3. Double-check the field name is exactly "message".

Example fix

# before
payload["message"] = event_text.strip()
# after
payload["message"] = event_text.strip() or "GitHub event received"
Defensive patterns

Strategy: validation

Validate before calling

msg = payload.get('message')
if not isinstance(msg, str) or not msg.strip():
    raise ValueError('message must be non-empty text')

Type guard

def has_non_empty_message(payload: dict) -> bool:
    msg = payload.get('message')
    return isinstance(msg, str) and bool(msg.strip())

Try / catch

resp = requests.post(url, json=payload)
if resp.status_code == 400 and 'non-empty' in resp.json().get('error', ''):
    payload['message'] = 'GitHub event received'  # fallback text

Prevention

When it happens

Trigger: message omitted; set to ""; a string of only spaces/tabs/newlines; or sent as a number/list instead of a string.

Common situations: Empty GitHub event rendered to blank text; template collapses to whitespace; field name typo ('text'/'body' instead of 'message'); event type the template does not handle.

Related errors


AI-assisted analysis of OtterMind/Chat2DB@5ee1e990e7 (2026-08-14). Data as JSON: /api/errors/61200a4cfdbf1f15. Report an issue: GitHub.