huggingface/open-r1 · error · PistonError

{response}

Error message

{response}

What it means

After handling compilation, execute_ioi requires a 'run' key in the Piston response. If the response has no 'run' entry, the whole response object is raised as PistonError, because Piston only omits 'run' when the submission never actually executed (API-level failure, malformed response, or language/version not resolved).

Source

Thrown at src/open_r1/utils/competitive_programming/ioi_scoring.py:318


async def execute_ioi(client, data) -> tuple[str, str]:
    """
    Requests to the IOI package return the score as a float in the stdout, as well as optional feedback/errors in stderr.
    Returns a tuple of (score, feedback).
    """
    response = await client.send_execute(data)

    if "message" in response:
        raise PistonError(response["message"])

    if "compile" in response and response["compile"]["code"] != 0:
        return "0", "Compilation error exit code " + str(response["compile"]["code"]) + "\n" + response["compile"][
            "stderr"
        ]

    if "run" not in response:
        raise PistonError(response)

    if response["run"]["code"] == 1 and "MemoryError" in response["run"]["stderr"]:
        return "0", "Memory limit exceeded"

    # successful result
    if response["run"]["stdout"]:
        return response["run"]["stdout"], response["run"]["stderr"]

    if response["run"]["signal"] == "SIGKILL":
        return "0", "Time limit exceeded"

    # other issues
    if response["run"]["code"] != 0:
        raise PistonError(
            f"language={response['language']}, version={response['version']}, exit code={response['run']['code']}, stderr={response['run']['stderr']}, signal={response['run']['signal']}"
        )
    return "0", "Unknown error"

View on GitHub (pinned to 1416fa0cf2)

Solutions

  1. Inspect the full response printed in the error — it shows exactly what the endpoint returned and usually reveals the real cause (e.g. 'language cms_ioi not found').
  2. Confirm the endpoint exposes the cms_ioi runtime via GET /api/v2/runtimes; reinstall the IOI package if missing.
  3. Check for proxies/CDNs between client and worker that may strip or reshape the JSON response.
  4. Update the piston client/IOI package if the endpoint's response schema changed.

Example fix

// before: raw response dict in error
raise PistonError(response)
// after: log with context
raise PistonError(f"No 'run' in Piston response: {json.dumps(response)[:2000]}")
Defensive patterns

Strategy: validation

Validate before calling

required = {'compile', 'run'}
missing = required - set(response.keys())
if missing and 'message' not in response:
    raise RuntimeError(f'Unexpected Piston response shape, missing {missing}: {response}')

Type guard

def has_run_result(resp: dict) -> bool:
    run = resp.get('run') if isinstance(resp, dict) else None
    return isinstance(run, dict) and 'code' in run

Try / catch

try:
    result = await execute_ioi(client, data)
except PistonError as e:
    if 'cms_ioi not found' in str(e) or "'run'" in str(e):
        await mark_endpoint_unhealthy(endpoint)
    raise

Prevention

When it happens

Trigger: send_execute returns a dict lacking 'run' — typically a Piston error body that happened to carry no top-level 'message' key (e.g. partial/odd response shape from a proxy, or a runtime that failed to install), so the guard on 'message' at line ~310 didn't fire.

Common situations: Reverse proxy or load balancer in front of Piston rewriting error bodies; a custom IOI package whose language runtime failed to install on the worker; endpoint version mismatch returning an unexpected schema.

Related errors


AI-assisted analysis of huggingface/open-r1@1416fa0cf2 (2026-08-30). Data as JSON: /api/errors/394a7afa1e1d20a4. Report an issue: GitHub.