{"record":{"id":"1e35f1f62b01a478","repo":"XX-net/XX-Net","slug":"600","errorCode":"600","errorMessage":"get protocol head fail","messagePattern":"get protocol head fail","errorType":"exception","errorClass":"GAE_Exception","httpStatus":null,"severity":"error","filePath":"code/default/gae_proxy/local/gae_handler.py","lineNumber":285,"sourceCode":"            payload += b'X-URLFETCH-%s: %d\\r\\n' % (k, v)\n        else:\n            payload += b'X-URLFETCH-%s: %s\\r\\n' % (k, utils.to_bytes(v))\n\n    payload = deflate(payload)\n\n    body = b'%s%s%s' % (struct.pack('!h', len(payload)), payload, body)\n    request_headers = {}\n    request_headers[b'Content-Length'] = str(len(body))\n    # request_headers 只有上面一项\n\n    return request_headers, body\n\n\ndef unpack_response(response):\n    try:\n        data = response.task.read(size=2)\n        if not data:\n            raise GAE_Exception(600, \"get protocol head fail\")\n\n        if len(data) !=2:\n            raise GAE_Exception(600, \"get protocol head fail, data:%s, len:%d\" % (data, len(data)))\n\n        headers_length, = struct.unpack('!h', data)\n        data = response.task.read(size=headers_length)\n        if not data:\n            raise GAE_Exception(600,\n                \"get protocol head fail, len:%d\" % headers_length)\n\n        raw_response_line, headers_data = inflate(data).split(b'\\r\\n', 1)\n        rl = raw_response_line.split()\n        response.app_status = int(rl[1])\n        if len(rl) >=3:\n            response.app_reason = rl[2].strip()\n\n        headers_block, app_msg = headers_data.split(b'\\r\\n\\r\\n')\n        headers_pairs = headers_block.split(b'\\r\\n')","sourceCodeStart":267,"sourceCodeEnd":303,"githubUrl":"https://github.com/XX-net/XX-Net/blob/cfa5bc17b67676e467f37ec50766127e0ab5f0aa/code/default/gae_proxy/local/gae_handler.py#L267-L303","documentation":"GAE_Exception 600 thrown in unpack_response when the first 2-byte protocol header read from the GAE connection returns empty. The GAE proxy protocol prefixes each response with a 2-byte big-endian header length; an empty read means the server/connection closed before sending any payload, so the response cannot be parsed.","triggerScenarios":"Calling request_gae_proxy whose inner request_gae_server succeeded at HTTP level but the app returned zero bytes; the connection was closed (worker.close) or reset between the HTTP response and body read; server-side error producing empty body.","commonSituations":"GAE appid misbehaving or deleted, flaky connection to Google IPs, IP blocked/reset mid-response, GAE platform incident, protocol mismatch after XX-Net version change.","solutions":["Retry the request — the upper layer (request_gae_proxy) already retries; persistent failure means the appid or IP is bad","Update to the current XX-Net version so the protocol matches the deployed GAE app","Deploy/repair your GAE appid (check the appengine admin console for errors)","Switch to a different Google IP / let the IP manager re-scan working IPs"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    response = request_gae_proxy(method, url, headers, body)\nexcept GAE_Exception as e:\n    if e.code == 600:\n        # transport/protocol level; safe to retry on a new connection\n        response = request_gae_proxy(method, url, headers, body)\n    else:\n        raise","preventionTips":["Keep multiple healthy appids and IPs configured so retries land on good routes","Run the latest XX-Net version to avoid protocol mismatches","Treat repeated 600s from one IP/appid as a signal to bench it"],"tags":["gae-proxy","protocol","empty-response","network"],"backgroundTag":"empty-response-body","analyzedSha":"cfa5bc17b67676e467f37ec50766127e0ab5f0aa","analyzedAt":"2026-08-27T19:28:28.225Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}