{"record":{"id":"7a49259ca1398446","repo":"OtterMind/Chat2DB","slug":"content-length-is-required","errorCode":null,"errorMessage":"Content-Length is required","messagePattern":"Content-Length is required","errorType":"http","errorClass":"RequestError","httpStatus":411,"severity":"error","filePath":"script/github/qq_relay/relay_server.py","lineNumber":206,"sourceCode":"        self.send_header(\"Cache-Control\", \"no-store\")\n        self.send_header(\"X-Content-Type-Options\", \"nosniff\")\n        self.end_headers()\n        self.wfile.write(body)\n\n    def _authorize(self) -> None:\n        expected = f\"Bearer {self.relay_state.config.relay_token}\"\n        supplied = self.headers.get(\"Authorization\", \"\")\n        if not hmac.compare_digest(supplied, expected):\n            raise RequestError(HTTPStatus.UNAUTHORIZED, \"unauthorized\")\n\n    def _read_payload(self) -> Mapping[str, Any]:\n        content_type = self.headers.get(\"Content-Type\", \"\")\n        if not content_type.lower().startswith(\"application/json\"):\n            raise RequestError(HTTPStatus.UNSUPPORTED_MEDIA_TYPE, \"Content-Type must be JSON\")\n        try:\n            content_length = int(self.headers.get(\"Content-Length\", \"\"))\n        except ValueError as error:\n            raise RequestError(HTTPStatus.LENGTH_REQUIRED, \"Content-Length is required\") from error\n        if content_length < 1 or content_length > MAX_REQUEST_BYTES:\n            raise RequestError(HTTPStatus.REQUEST_ENTITY_TOO_LARGE, \"request body is too large\")\n        try:\n            payload = json.loads(self.rfile.read(content_length).decode(\"utf-8\"))\n        except (UnicodeDecodeError, json.JSONDecodeError) as error:\n            raise RequestError(HTTPStatus.BAD_REQUEST, \"request body is not valid JSON\") from error\n        if not isinstance(payload, Mapping):\n            raise RequestError(HTTPStatus.BAD_REQUEST, \"request body must be a JSON object\")\n        return payload\n\n    def _validate_payload(self, payload: Mapping[str, Any]) -> tuple[str, str]:\n        config = self.relay_state.config\n        if payload.get(\"repository\") != config.repository:\n            raise RequestError(HTTPStatus.FORBIDDEN, \"repository is not allowed\")\n        delivery_id = payload.get(\"delivery_id\")\n        if not isinstance(delivery_id, str) or not DELIVERY_ID_PATTERN.fullmatch(delivery_id):\n            raise RequestError(HTTPStatus.BAD_REQUEST, \"delivery_id is invalid\")\n        message = payload.get(\"message\")","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/OtterMind/Chat2DB/blob/5ee1e990e73fbcae1969dc554be254fedb3ab888/script/github/qq_relay/relay_server.py#L188-L224","documentation":"Raised by RelayHandler._read_payload (relay_server.py:206) as a RequestError(HTTP 411) when the Content-Length header is missing or not parseable as an integer. The relay reads exactly Content-Length bytes, so a missing/unparseable value is rejected. A chunked-transfer request without a Content-Length also hits this.","triggerScenarios":"A POST with no Content-Length header, or a Content-Length value that is non-numeric. The bundled notifier (urllib) always sets Content-Length, so this is usually a manual client, a chunked client, or a proxy that removed the header.","commonSituations":"curl with chunked transfer encoding; a client using Transfer-Encoding: chunked without Content-Length; a proxy stripping Content-Length; a hand-crafted request omitting the header.","solutions":["Send a valid integer Content-Length matching the body size.","Avoid chunked transfer; send a fixed-length body so the client sets Content-Length.","If a proxy is involved, ensure it forwards Content-Length unchanged."],"exampleFix":"curl -X POST https://relay.example.com/v1/qq/github \\\n  -H \"Authorization: Bearer $RELAY_TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Content-Length: 123\" \\\n  --data-binary @body.json","handlingStrategy":"validation","validationCode":"try:\n    content_length = int(headers.get(\"Content-Length\", \"\"))\nexcept ValueError:\n    headers[\"Content-Length\"] = str(len(body))","typeGuard":"def has_valid_content_length(headers: Mapping[str, str]) -> bool:\n    try:\n        return int(headers.get(\"Content-Length\", \"\")) >= 1\n    except ValueError:\n        return False","tryCatchPattern":null,"preventionTips":["Send fixed-length bodies so the client sets Content-Length automatically.","Avoid chunked transfer encoding when calling the relay."],"tags":["http","relay","validation"],"backgroundTag":null,"analyzedSha":"5ee1e990e73fbcae1969dc554be254fedb3ab888","analyzedAt":"2026-08-14T07:05:03.077Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}