Skip to content

fix(inference): a GPU decode step that fails mid-generation is an error - #796

Merged
chrishayuk merged 3 commits into
mainfrom
inference/gpu-decode-step-failure
Nov 12, 2026
Merged

chrishayuk merged 3 commits into
mainfrom
inference/gpu-decode-step-failure

Conversation

@chrishayuk

Copy link
Copy Markdown
Owner

A GPU decode step that fails mid-generation is an error

What was wrong

The fused GPU decode loop has two exits for a step that went wrong: the backend returned nothing for the step, or the step produced no candidate tokens (which is how the backend reports a failed command buffer). Both did break, and the loop returned the tokens it had. generate_streaming then built the GenerateResult with error: None. A generation cut short by a GPU fault came back as a complete, successful one, just shorter.

What changes

DecodeLoopOutcome carries error: Option<GenerateError>, set at both exits with the step number and how many tokens the loop had produced. generate_streaming puts it on the result, alongside the tokens generated before the failure. A loop that ends at max_tokens or an end-of-sequence token still has no error.

MockGpuBackend::failing_after(steps) makes the mock's decode_token answer None after a number of successful steps, so this path is testable.

Evidence

a_gpu_decode_step_that_fails_mid_generation_is_reported runs the public generate with the mock: a backend that never fails produces max_tokens tokens and no error (the control); one that fails after two steps produces fewer tokens and must carry an error. With main's decode loop and caller (df20de1e) and the new mock, the test fails at "a generation cut short by a failed step must carry an error". With the fix it passes, as does a second test on the loop directly.

Full larql-inference suite: 1,974 passed, 0 failed. cargo fmt --check and cargo clippy -p larql-inference --lib --tests --benches --no-deps -D warnings clean.

Not covered

  • Tested with the mock backend only; I did not induce a real Metal command-buffer failure.
  • How the server turns this error into a response mid-stream (after tokens have been sent) was not changed or tested here. Before this change the server could not tell at all.
  • The CPU fallback's equivalent is in PR 795.

chrishayuk and others added 3 commits November 12, 2026 01:34
When the backend returned nothing for a decode step, or a step produced
no candidate tokens (how a failed command buffer is reported), the
decode loop stopped and returned the tokens it had. The caller built the
result with error: None, so a generation cut short by a GPU fault was
reported as a complete one.

The loop now returns the reason with its outcome, and the result carries
it as an error alongside the tokens produced before the failure. The
mock GPU backend can be told to fail after a number of steps.
@chrishayuk
chrishayuk merged commit 2633a19 into main Nov 12, 2026
35 checks passed
@chrishayuk
chrishayuk deleted the inference/gpu-decode-step-failure branch November 12, 2026 12:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant