An out-of-order access — a common user mistake — is diagnosed correctly on the trusted path and reported as an opaque IPC failure on the untrusted path. Untrusted is the default for real users, so this is the error most people will actually hit.
Reproduction
with model.trace("the " * 64, remote=True):
lg = model.lm_head.output.save() # runs LAST
h0 = model.transformer.h[0].output[0].save() # runs FIRST -> already passed
| path |
what the user sees |
| trusted |
OutOfOrderError: 'model.transformer.h.0.output.i0' was requested but the model already ran past it |
| untrusted |
BrokenPipeError: [Errno 32] Broken pipe |
The same block in the correct order completes on both paths. Fully reproducible.
Mechanism
From the model actor's log for the untrusted request, the runner does raise the right error:
File "/w/outoforder.py", line 19, in out_of_order
h0 = m.transformer.h[0].output[0].save()
value = Mediator.value(location)
return cls.event(Event.VALUE, location)
return worker.parent.switch(Pending(event, location, iteration, *rest))
nnsight.intervention.interleaver.OutOfOrderError: 'model.transformer.h.0.output.i0' was requested but the model already ran past it
and then, on the host side:
return driver.pump(connection)
self.interleave(connection, fn_name, parks, args, kwargs)
connection.send(("DONE", result))
self.send_raw(encode(value))
send_frame(self.sock, data)
sock.sendall(struct.pack(">Q", len(data)) + data)
BrokenPipeError: [Errno 32] Broken pipe
The host detects the dangling worker and THROWs OutOfOrderError into the runner. The runner raises it and terminates. The host then writes ("DONE", result) to a socket whose peer is already gone, and the resulting BrokenPipeError is what gets reported — the thrown error is never collected.
The misdiagnosis reaches telemetry as well. Two requests, same block, seconds apart:
error_type=OutOfOrderError ... email=loadtest-trusted@ndif.us exec_ms=22.12
error_type=BrokenPipeError ... email=loadtest-untrusted@ndif.us exec_ms=292.04
so error-rate breakdowns attribute a user error to infrastructure.
Suggested
After THROWing into a worker, the host should treat a subsequent write failure as "the runner died from the error I just threw" and report that error rather than the pipe error — or collect the runner's terminal state before sending DONE. Any error the host itself throws in is already known to it, so it does not need to survive the round trip.
Observed on the Test deployment, ndif 0.8 @ be38d78, nnsight 0.8 @ 3bed88cc.
An out-of-order access — a common user mistake — is diagnosed correctly on the trusted path and reported as an opaque IPC failure on the untrusted path. Untrusted is the default for real users, so this is the error most people will actually hit.
Reproduction
OutOfOrderError: 'model.transformer.h.0.output.i0' was requested but the model already ran past itBrokenPipeError: [Errno 32] Broken pipeThe same block in the correct order completes on both paths. Fully reproducible.
Mechanism
From the model actor's log for the untrusted request, the runner does raise the right error:
and then, on the host side:
The host detects the dangling worker and THROWs
OutOfOrderErrorinto the runner. The runner raises it and terminates. The host then writes("DONE", result)to a socket whose peer is already gone, and the resultingBrokenPipeErroris what gets reported — the thrown error is never collected.The misdiagnosis reaches telemetry as well. Two requests, same block, seconds apart:
so error-rate breakdowns attribute a user error to infrastructure.
Suggested
After THROWing into a worker, the host should treat a subsequent write failure as "the runner died from the error I just threw" and report that error rather than the pipe error — or collect the runner's terminal state before sending DONE. Any error the host itself throws in is already known to it, so it does not need to survive the round trip.
Observed on the Test deployment, ndif 0.8 @ be38d78, nnsight 0.8 @ 3bed88cc.