During torch.onnx.export, you got something like:

stack trace
RuntimeError: torch.jit.script failed for module <...> Encountered control flow that could not be captured statically.

This means the legacy ONNX exporter tried to capture your model's control flow (an if, a for, an LSTM's internal loop) using TorchScript, and the scripting failed. Three fixes, in order of preference:

Fix 1: remove the dynamic axis that forced the loop

Almost always, this error comes from making a dimension dynamic that doesn't need to be — usually sequence length on an LSTM. Set it static and the loop is unrolled at export, no scripting needed.

before / after
# Bad: seq_len dynamic, triggers scripting dynamic_axes={"input": {0: "batch", 1: "seq"}} # Good: only batch dynamic dynamic_axes={"input": {0: "batch"}}

See dynamic_axes explained for the full rule.

Fix 2: trace instead of script

If the dynamic axis is genuinely needed, force tracing-based export. PyTorch's legacy exporter uses tracing by default for most ops and falls back to scripting only when control flow is encountered. You can disable the fallback:

torch.onnx.export with tracing-only
torch.onnx.export( model, dummy, "model.onnx", opset_version=17, operator_export_type=torch.onnx.OperatorExportTypes.ONNX, do_constant_folding=True, )

This is the default behavior — included as a sanity check. If the error persists, the model genuinely needs scripting.

Fix 3: try the new exporter (dynamo)

PyTorch 2.x ships a newer ONNX exporter based on TorchDynamo that handles control flow better:

dynamo exporter
torch.onnx.export( model, dummy, "model.onnx", opset_version=17, dynamo=True, # the new exporter )

Caveats: the dynamo exporter is newer, less battle-tested, and produces slightly different graphs that may or may not load cleanly in MT5. Always validate the result by comparing PyTorch and ONNX outputs (see the validation step).

Diagnosing: which op caused it?

The stack trace usually names the offending module. If it's an LSTM, you have the seq_len-dynamic problem. If it's your own nn.Module with an if statement inside forward, you have a "branching at inference" pattern that ONNX can't capture — rewrite the branch as a multiplication by a 0/1 mask, or split the model into two paths chosen on the MQL5 side.