{"record":{"id":"a853a5d91ce0c1c8","repo":"huggingface/open-r1","slug":"server-error-status-status-res-json","errorCode":null,"errorMessage":"Server error. status={status}. {res_json}","messagePattern":"Server error\\. status=(.+?)\\. (.+?)","errorType":"http","errorClass":"PistonError","httpStatus":null,"severity":"error","filePath":"src/open_r1/utils/competitive_programming/piston_client.py","lineNumber":160,"sourceCode":"\n        base_delay = 1.0\n\n        status = None\n        endpoint = None\n\n        for attempt in range(max_retries + 1):\n            try:\n                endpoint = await self._wait_for_endpoint()\n                if attempt > 0:\n                    await asyncio.sleep(1)\n                async with self.session.post(\n                    f\"{endpoint.rstrip('/')}/execute\", json=data, headers={\"Content-Type\": \"application/json\"}\n                ) as response:\n                    status = response.status\n                    res_json = await response.json(content_type=None)\n\n                    if status != 200:\n                        raise PistonError(f\"Server error. status={status}. {res_json}\")\n                    if res_json is None:\n                        raise PistonError(f\"Empty response. status={status}\")\n                    # piston overloaded\n                    if \"run\" in res_json and \"Resource temporarily unavailable\" in res_json[\"run\"].get(\"stderr\", \"\"):\n                        raise PistonError(f\"Piston overloaded: {res_json['run']['stderr']}\")\n                    return res_json\n\n            except (PistonError, asyncio.TimeoutError, aiohttp.ClientConnectionError, RuntimeError) as e:\n                # Only retry if we haven't reached max retries yet\n                if attempt < max_retries:\n                    # Calculate backoff with jitter\n                    delay = min(base_delay * (2**attempt), 10)  # Exponential backoff, capped at 10 seconds\n                    jitter = delay * 0.2 * (2 * asyncio.get_event_loop().time() % 1 - 0.5)  # Add ±10% jitter\n                    retry_delay = delay + jitter\n                    print(f\"Retrying in {retry_delay:.2f} seconds [{self.endpoint_ids[endpoint]}] {endpoint} - {e}\")\n\n                    # special case: worker died\n                    if isinstance(e, aiohttp.ClientConnectionError) and \"Connect call failed\" in str(e):","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/huggingface/open-r1/blob/1416fa0cf21595d2083b399a2a0bbddd7f6e9563/src/open_r1/utils/competitive_programming/piston_client.py#L142-L178","documentation":"PistonClient.send_execute raises PistonError('Server error. status=...') when the Piston worker's /execute HTTP endpoint returns a status code other than 200. The response body (res_json) is included in the message to surface the server's own error description. It signals a server-side rejection such as bad payload, rate limiting, or gateway errors.","triggerScenarios":"POST to {endpoint}/execute returns 4xx/5xx (e.g. 400 malformed payload, 429 rate limit, 502/503 gateway down, 404 wrong endpoint URL). The client retries up to max_retries (default 5) with exponential backoff before giving up.","commonSituations":"Misconfigured PISTON_ENDPOINT_URL (missing /api/v2 path, wrong port), Piston worker overloaded or restarting behind a load balancer, payload with invalid fields (bad language version), reverse proxy returning HTML error pages.","solutions":["Read the status and body in the message to identify the server-side cause","Verify the piston endpoint URL is reachable and points at /api/v2 (curl {endpoint}/api/v2/runtimes)","Check Piston worker logs/health; restart or scale workers if 502/503/429","Fix the execute payload (language, version, files) if status is 400","Increase max_retries or add client-side pacing if hitting rate limits"],"exampleFix":"// before\nclient = PistonClient(base_endpoints=[\"http://piston:2000\"])  # 404 on /execute\n// after\nclient = PistonClient(base_endpoints=[\"http://piston:2000/api/v2\"])","handlingStrategy":"retry","validationCode":"import aiohttp\nasync def endpoint_ok(url):\n    try:\n        async with aiohttp.ClientSession() as s:\n            async with s.get(f\"{url.rstrip('/')}/runtimes\", timeout=aiohttp.ClientTimeout(total=5)) as r:\n                return r.status == 200\n    except Exception:\n        return False","typeGuard":"def is_http_ok(status, body):\n    return isinstance(status, int) and status == 200 and isinstance(body, dict)","tryCatchPattern":"try:\n    res = await client.send_execute(data)\nexcept PistonError as e:\n    if str(e).startswith(\"Server error\"):\n        logger.warning(\"Piston HTTP failure, falling back: %s\", e)\n        res = run_locally(data)  # or requeue\n    else:\n        raise","preventionTips":["Health-check endpoints (/runtimes) before executing and drop unhealthy ones","Keep the API path correct (/api/v2) in endpoint configuration","Monitor worker 5xx/429 rates and scale the Piston fleet","Set a sane max_retries and alert when retries are exhausted"],"tags":["http","api","network","retry"],"backgroundTag":"http-5xx-server-error","analyzedSha":"1416fa0cf21595d2083b399a2a0bbddd7f6e9563","analyzedAt":"2026-08-30T08:56:53.400Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}